[llvm] [CodeGen] SparseLiveVariables: A liveness analysis pass (PR #167454)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 22 07:15:57 PDT 2026


https://github.com/hiraditya updated https://github.com/llvm/llvm-project/pull/167454

>From 9e26e342d0f80c61690dcfc7268d5a6dfd8f02c4 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Mon, 10 Nov 2025 20:49:02 -0800
Subject: [PATCH 01/32] [RISCV64] Add live variable analysis pass

---
 llvm/lib/Target/RISCV/CMakeLists.txt         |   1 +
 llvm/lib/Target/RISCV/RISCV.h                |   3 +
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp | 428 +++++++++++++++++++
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp |   3 +
 4 files changed, 435 insertions(+)
 create mode 100644 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp

diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index 3b529c1471d54..d94d40ebadcc3 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -51,6 +51,7 @@ add_llvm_target(RISCVCodeGen
   RISCVISelLowering.cpp
   RISCVLandingPadSetup.cpp
   RISCVLateBranchOpt.cpp
+  RISCVLiveVariables.cpp
   RISCVLoadStoreOptimizer.cpp
   RISCVMachineFunctionInfo.cpp
   RISCVMakeCompressible.cpp
diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h
index 048db205e2289..9fb6a603e481d 100644
--- a/llvm/lib/Target/RISCV/RISCV.h
+++ b/llvm/lib/Target/RISCV/RISCV.h
@@ -108,6 +108,9 @@ void initializeRISCVPreAllocZilsdOptPass(PassRegistry &);
 FunctionPass *createRISCVZacasABIFixPass();
 void initializeRISCVZacasABIFixPass(PassRegistry &);
 
+FunctionPass *createRISCVLiveVariablesPass();
+void initializeRISCVLiveVariablesPass(PassRegistry &);
+
 InstructionSelector *
 createRISCVInstructionSelector(const RISCVTargetMachine &,
                                const RISCVSubtarget &,
diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
new file mode 100644
index 0000000000000..b8eb6614470b9
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -0,0 +1,428 @@
+//===- RISCVLiveVariables.cpp - Live Variable Analysis for RISC-V --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a live variable analysis pass for the RISC-V backend.
+// The pass computes liveness information for virtual and physical registers
+// in RISC-V machine functions, optimized for RV64 (64-bit RISC-V architecture).
+//
+// The analysis performs a backward dataflow analysis to compute:
+// - Live-in sets: Registers that are live at the entry of a basic block
+// - Live-out sets: Registers that are live at the exit of a basic block
+// - Kill points: Instructions where a register's last use occurs
+// - Def points: Instructions where a register is defined
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCV.h"
+#include "RISCVInstrInfo.h"
+#include "RISCVSubtarget.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <set>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "riscv-live-variables"
+#define RISCV_LIVE_VARIABLES_NAME "RISC-V Live Variable Analysis"
+
+STATISTIC(NumLiveRegsAtEntry, "Number of registers live at function entry");
+STATISTIC(NumLiveRegsTotal, "Total number of live registers across all blocks");
+
+namespace {
+
+/// LivenessInfo - Stores liveness information for a basic block
+/// TODO: Optimize storage using BitVectors for large register sets.
+struct LivenessInfo {
+  /// Registers that are live into this block
+  /// LiveIn[B] = Use[B] U (LiveOut[B] - Def[B])
+  std::set<Register> LiveIn;
+
+  /// Registers that are live out of this block.
+  /// LiveOut[B] = U LiveIns[∀ Succ(B)].
+  std::set<Register> LiveOut;
+
+  /// Registers that are defined in this block
+  std::set<Register> Def;
+
+  /// Registers that are used in this block before being defined (if at all).
+  std::set<Register> Use;
+};
+
+class RISCVLiveVariables : public MachineFunctionPass {
+public:
+  static char ID;
+
+  RISCVLiveVariables() : MachineFunctionPass(ID) {
+    initializeRISCVLiveVariablesPass(*PassRegistry::getPassRegistry());
+  }
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesAll();
+    MachineFunctionPass::getAnalysisUsage(AU);
+  }
+
+  StringRef getPassName() const override { return RISCV_LIVE_VARIABLES_NAME; }
+
+  /// Returns the set of registers live at the entry of the given basic block
+  const std::set<Register> &getLiveInSet(const MachineBasicBlock *MBB) const {
+    auto It = BlockLiveness.find(MBB);
+    assert(It != BlockLiveness.end() && "Block not analyzed");
+    return It->second.LiveIn;
+  }
+
+  /// Returns the set of registers live at the exit of the given basic block
+  const std::set<Register> &getLiveOutSet(const MachineBasicBlock *MBB) const {
+    auto It = BlockLiveness.find(MBB);
+    assert(It != BlockLiveness.end() && "Block not analyzed");
+    return It->second.LiveOut;
+  }
+
+  /// Check if a register is live at a specific instruction
+  bool isLiveAt(Register Reg, const MachineInstr &MI) const;
+
+  /// Print liveness information for debugging
+  void print(raw_ostream &OS, const Module *M = nullptr) const override;
+
+private:
+  /// Compute local liveness information (Use and Def sets) for each block
+  void computeLocalLiveness(MachineFunction &MF);
+
+  /// Compute global liveness information (LiveIn and LiveOut sets)
+  void computeGlobalLiveness(MachineFunction &MF);
+
+  /// Process a single instruction to extract def/use information
+  void processInstruction(const MachineInstr &MI, LivenessInfo &Info,
+                          const TargetRegisterInfo *TRI);
+
+  /// Check if a register is allocatable (relevant for liveness tracking)
+  bool isTrackableRegister(Register Reg, const TargetRegisterInfo *TRI,
+                           const MachineRegisterInfo *MRI) const;
+
+  /// Liveness information for each basic block
+  DenseMap<const MachineBasicBlock *, LivenessInfo> BlockLiveness;
+
+  /// Cached pointer to MachineRegisterInfo
+  const MachineRegisterInfo *MRI;
+
+  /// Cached pointer to TargetRegisterInfo
+  const TargetRegisterInfo *TRI;
+};
+
+} // end anonymous namespace
+
+char RISCVLiveVariables::ID = 0;
+
+INITIALIZE_PASS(RISCVLiveVariables, DEBUG_TYPE, RISCV_LIVE_VARIABLES_NAME,
+                false, true)
+
+FunctionPass *llvm::createRISCVLiveVariablesPass() {
+  return new RISCVLiveVariables();
+}
+
+bool RISCVLiveVariables::isTrackableRegister(
+    Register Reg, const TargetRegisterInfo *TRI,
+    const MachineRegisterInfo *MRI) const {
+  // Track virtual registers
+  if (Reg.isVirtual())
+    return true;
+
+  // For physical registers, only track allocatable ones
+  if (Reg.isPhysical()) {
+    // Check if register is allocatable
+    if (!TRI->isInAllocatableClass(Reg))
+      return false;
+
+    // Track general purpose registers (X0-X31)
+    // Track floating point registers (F0-F31)
+    // Track vector registers for RVV if present
+    return true;
+  }
+
+  return false;
+}
+
+void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
+                                             LivenessInfo &Info,
+                                             const TargetRegisterInfo *TRI) {
+  // Process all operands
+  for (const MachineOperand &MO : MI.operands()) {
+    if (!MO.isReg() || !MO.getReg())
+      continue;
+
+    Register Reg = MO.getReg();
+
+    // Skip non-trackable registers
+    if (!isTrackableRegister(Reg, TRI, MRI))
+      continue;
+
+    if (MO.isDef()) {
+      // This is a definition
+      Info.Def.insert(Reg);
+
+      // Also handle sub-registers for physical registers
+      if (Reg.isPhysical()) {
+        for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
+             SubRegs.isValid(); ++SubRegs) {
+          Info.Def.insert(*SubRegs);
+        }
+      }
+    }
+
+    if (MO.isUse()) {
+      // This is a use - only add to Use set if not already defined in this block
+      if (Info.Def.find(Reg) == Info.Def.end()) {
+        Info.Use.insert(Reg);
+
+        // Also handle sub-registers for physical registers
+        if (Reg.isPhysical()) {
+          for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
+               SubRegs.isValid(); ++SubRegs) {
+            if (Info.Def.find(*SubRegs) == Info.Def.end()) {
+              Info.Use.insert(*SubRegs);
+            }
+          }
+        }
+      }
+    }
+
+    // Handle implicit operands (like condition codes, stack pointer updates)
+    if (MO.isImplicit() && MO.isUse() && Reg.isPhysical()) {
+      if (Info.Def.find(Reg) == Info.Def.end()) {
+        Info.Use.insert(Reg);
+      }
+    }
+  }
+
+  // Handle RegMasks (from calls) - they kill all non-preserved registers
+  for (const MachineOperand &MO : MI.operands()) {
+    if (MO.isRegMask()) {
+      const uint32_t *RegMask = MO.getRegMask();
+
+      // Iterate through all physical registers
+      for (unsigned PhysReg = 1; PhysReg < TRI->getNumRegs(); ++PhysReg) {
+        // If the register is not preserved by this mask, it's clobbered
+        if (!MachineOperand::clobbersPhysReg(RegMask, PhysReg))
+          continue;
+
+        // Mark as defined (clobbered)
+        if (isTrackableRegister(Register(PhysReg), TRI, MRI)) {
+          Info.Def.insert(Register(PhysReg));
+        }
+      }
+    }
+  }
+}
+
+void RISCVLiveVariables::computeLocalLiveness(MachineFunction &MF) {
+  LLVM_DEBUG(dbgs() << "Computing local liveness for " << MF.getName() << "\n");
+
+  // Process each basic block
+  for (MachineBasicBlock &MBB : MF) {
+    LivenessInfo &Info = BlockLiveness[&MBB];
+    Info.Def.clear();
+    Info.Use.clear();
+
+    // Process instructions in forward order to build Use and Def sets
+    for (const MachineInstr &MI : MBB) {
+      // Skip debug instructions and meta instructions
+      if (MI.isDebugInstr() || MI.isMetaInstruction())
+        continue;
+
+      processInstruction(MI, Info, TRI);
+    }
+
+    LLVM_DEBUG({
+      dbgs() << "Block " << MBB.getName() << ":\n";
+      dbgs() << "  Use: ";
+      for (Register Reg : Info.Use)
+        dbgs() << printReg(Reg, TRI) << " ";
+      dbgs() << "\n  Def: ";
+      for (Register Reg : Info.Def)
+        dbgs() << printReg(Reg, TRI) << " ";
+      dbgs() << "\n";
+    });
+  }
+}
+
+void RISCVLiveVariables::computeGlobalLiveness(MachineFunction &MF) {
+  LLVM_DEBUG(dbgs() << "Computing global liveness (fixed-point iteration)\n");
+
+  bool Changed = true;
+  unsigned Iterations = 0;
+
+  // Iterate until we reach a fixed point
+  // Live-out[B] = Union of Live-in[S] for all successors S of B
+  // Live-in[B] = Use[B] Union (Live-out[B] - Def[B])
+  while (Changed) {
+    Changed = false;
+    ++Iterations;
+
+    // Process blocks in reverse post-order for better convergence
+    ReversePostOrderTraversal<MachineFunction *> RPOT(&MF);
+
+    for (MachineBasicBlock *MBB : RPOT) {
+      LivenessInfo &Info = BlockLiveness[MBB];
+      std::set<Register> OldLiveIn = Info.LiveIn;
+      std::set<Register> NewLiveOut;
+
+      // Compute Live-out: Union of Live-in of all successors
+      for (MachineBasicBlock *Succ : MBB->successors()) {
+        LivenessInfo &SuccInfo = BlockLiveness[Succ];
+        NewLiveOut.insert(SuccInfo.LiveIn.begin(), SuccInfo.LiveIn.end());
+      }
+
+      Info.LiveOut = NewLiveOut;
+
+      // Compute Live-in: Use Union (Live-out - Def)
+      std::set<Register> NewLiveIn = Info.Use;
+
+      for (Register Reg : Info.LiveOut) {
+        if (Info.Def.find(Reg) == Info.Def.end()) {
+          NewLiveIn.insert(Reg);
+        }
+      }
+
+      Info.LiveIn = NewLiveIn;
+
+      // Check if anything changed
+      if (Info.LiveIn != OldLiveIn) {
+        Changed = true;
+      }
+    }
+  }
+
+  LLVM_DEBUG(dbgs() << "Global liveness converged in " << Iterations
+                    << " iterations\n");
+
+  // Update statistics
+  for (auto &Entry : BlockLiveness) {
+    NumLiveRegsTotal += Entry.second.LiveIn.size();
+  }
+
+  // Count live registers at function entry
+  if (!MF.empty()) {
+    const MachineBasicBlock &EntryBB = MF.front();
+    NumLiveRegsAtEntry += BlockLiveness[&EntryBB].LiveIn.size();
+  }
+}
+
+bool RISCVLiveVariables::isLiveAt(Register Reg,
+                                   const MachineInstr &MI) const {
+  const MachineBasicBlock *MBB = MI.getParent();
+  auto It = BlockLiveness.find(MBB);
+
+  if (It == BlockLiveness.end())
+    return false;
+
+  const LivenessInfo &Info = It->second;
+
+  // A register is live at an instruction if:
+  // 1. It's in the live-in set of the block, OR
+  // 2. It's defined before this instruction and used after (not yet killed)
+
+  // Check if it's live-in to the block
+  if (Info.LiveIn.count(Reg))
+    return true;
+
+  // For a more precise answer, we'd need to track instruction-level liveness
+  // For now, conservatively return true if it's in live-out and not killed yet
+  if (Info.LiveOut.count(Reg))
+    return true;
+
+  return false;
+}
+
+bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
+  if (skipFunction(MF.getFunction()))
+    return false;
+
+  const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
+
+  // Verify we're targeting RV64
+  if (!Subtarget.is64Bit()) {
+    LLVM_DEBUG(dbgs() << "Warning: RISCVLiveVariables optimized for RV64, "
+                      << "but running on RV32\n");
+    return false;
+  }
+
+  MRI = &MF.getRegInfo();
+  TRI = Subtarget.getRegisterInfo();
+
+  LLVM_DEBUG(dbgs() << "***** RISC-V Live Variable Analysis *****\n");
+  LLVM_DEBUG(dbgs() << "Function: " << MF.getName() << "\n");
+  LLVM_DEBUG(dbgs() << "Target: RV" << (Subtarget.is64Bit() ? "64" : "32")
+                    << "\n");
+
+  // Clear any previous analysis
+  BlockLiveness.clear();
+
+  // Step 1: Compute local liveness (Use and Def sets)
+  computeLocalLiveness(MF);
+
+  // Step 2: Compute global liveness (LiveIn and LiveOut sets)
+  computeGlobalLiveness(MF);
+
+  LLVM_DEBUG({
+    dbgs() << "\n***** Final Liveness Information *****\n";
+    print(dbgs());
+  });
+
+  // This is an analysis pass, it doesn't modify the function
+  return false;
+}
+
+void RISCVLiveVariables::print(raw_ostream &OS, const Module *M) const {
+  OS << "RISC-V Live Variable Analysis Results:\n";
+  OS << "======================================\n\n";
+
+  for (const auto &Entry : BlockLiveness) {
+    const MachineBasicBlock *MBB = Entry.first;
+    const LivenessInfo &Info = Entry.second;
+
+    OS << "Block: " << MBB->getName() << " (Number: " << MBB->getNumber()
+       << ")\n";
+
+    OS << "  Live-In:  { ";
+    for (Register Reg : Info.LiveIn) {
+      OS << printReg(Reg, TRI) << " ";
+    }
+    OS << "}\n";
+
+    OS << "  Live-Out: { ";
+    for (Register Reg : Info.LiveOut) {
+      OS << printReg(Reg, TRI) << " ";
+    }
+    OS << "}\n";
+
+    OS << "  Use:      { ";
+    for (Register Reg : Info.Use) {
+      OS << printReg(Reg, TRI) << " ";
+    }
+    OS << "}\n";
+
+    OS << "  Def:      { ";
+    for (Register Reg : Info.Def) {
+      OS << printReg(Reg, TRI) << " ";
+    }
+    OS << "}\n\n";
+  }
+}
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 54b286d128dfa..bbb6be2cf5d30 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -126,6 +126,7 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
   initializeRISCVPostLegalizerCombinerPass(*PR);
   initializeKCFIPass(*PR);
   initializeRISCVDeadRegisterDefinitionsPass(*PR);
+  initializeRISCVLiveVariablesPass(*PR);
   initializeRISCVLateBranchOptPass(*PR);
   initializeRISCVMakeCompressibleOptPass(*PR);
   initializeRISCVGatherScatterLoweringPass(*PR);
@@ -583,6 +584,7 @@ void RISCVPassConfig::addPreEmitPass() {
   addPass(createRISCVIndirectBranchTrackingPass());
   addPass(&BranchRelaxationPassID);
   addPass(createRISCVMakeCompressibleOptPass());
+  addPass(createRISCVLiveVariablesPass());
 }
 
 void RISCVPassConfig::addPreEmitPass2() {
@@ -620,6 +622,7 @@ void RISCVPassConfig::addMachineSSAOptimization() {
   TargetPassConfig::addMachineSSAOptimization();
 
   if (TM->getTargetTriple().isRISCV64()) {
+    addPass(createRISCVLiveVariablesPass());
     addPass(createRISCVOptWInstrsPass());
   }
 }

>From 5e31a54c84b825c823fa31c408f73a13c56476b0 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Mon, 10 Nov 2025 20:49:02 -0800
Subject: [PATCH 02/32] Add tests

---
 .../CodeGen/RISCV/live-variables-basic.mir    | 148 +++++++++
 .../CodeGen/RISCV/live-variables-calls.mir    | 214 +++++++++++++
 .../RISCV/live-variables-edge-cases.mir       | 285 ++++++++++++++++++
 .../CodeGen/RISCV/live-variables-loops.mir    | 238 +++++++++++++++
 .../CodeGen/RISCV/live-variables-rv64.mir     | 188 ++++++++++++
 5 files changed, 1073 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/live-variables-basic.mir
 create mode 100644 llvm/test/CodeGen/RISCV/live-variables-calls.mir
 create mode 100644 llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir
 create mode 100644 llvm/test/CodeGen/RISCV/live-variables-loops.mir
 create mode 100644 llvm/test/CodeGen/RISCV/live-variables-rv64.mir

diff --git a/llvm/test/CodeGen/RISCV/live-variables-basic.mir b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
new file mode 100644
index 0000000000000..741a8eafa1c27
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
@@ -0,0 +1,148 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv64 -run-pass=riscv-live-variables -verify-machineinstrs -o - %s | FileCheck %s
+#
+# Test basic live variable analysis with simple control flow and basic blocks
+
+--- |
+  define i64 @test_simple_add(i64 %a, i64 %b) {
+  entry:
+    %sum = add i64 %a, %b
+    ret i64 %sum
+  }
+
+  define i64 @test_if_then_else(i64 %a, i64 %b) {
+  entry:
+    %cmp = icmp sgt i64 %a, %b
+    br i1 %cmp, label %then, label %else
+
+  then:
+    %mul = mul i64 %a, %b
+    br label %end
+
+  else:
+    %sub = sub i64 %a, %b
+    br label %end
+
+  end:
+    %result = phi i64 [ %mul, %then ], [ %sub, %else ]
+    ret i64 %result
+  }
+
+  define i64 @test_multiple_uses(i64 %a, i64 %b, i64 %c) {
+  entry:
+    %t1 = add i64 %a, %b
+    %t2 = mul i64 %t1, %c
+    %t3 = sub i64 %t2, %a
+    %t4 = add i64 %t3, %b
+    ret i64 %t4
+  }
+...
+---
+name:            test_simple_add
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: test_simple_add
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: liveins: $x10, $x11
+    ; Test that %0 and %1 are live-in, used once, and %2 is defined
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = ADD %0, %1
+    $x10 = COPY %2
+    PseudoRET implicit $x10
+...
+---
+name:            test_if_then_else
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: test_if_then_else
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: successors
+    ; CHECK-NEXT: liveins: $x10, $x11
+    ; Test that %0 and %1 are live across multiple blocks
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = SLT %1, %0
+    BEQ %2, $x0, %bb.2
+
+  bb.1.then:
+    ; CHECK: bb.1.then:
+    ; %0 and %1 should be live-in here
+    %3:gpr = MUL %0, %1
+    PseudoBR %bb.3
+
+  bb.2.else:
+    ; CHECK: bb.2.else:
+    ; %0 and %1 should be live-in here
+    %4:gpr = SUB %0, %1
+    PseudoBR %bb.3
+
+  bb.3.end:
+    ; CHECK: bb.3.end:
+    ; Either %3 or %4 should be live-in (phi sources)
+    %5:gpr = PHI %3, %bb.1, %4, %bb.2
+    $x10 = COPY %5
+    PseudoRET implicit $x10
+...
+---
+name:            test_multiple_uses
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+  - { id: 6, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+  - { reg: '$x12', virtual-reg: '%2' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11, $x12
+    ; CHECK-LABEL: name: test_multiple_uses
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: liveins: $x10, $x11, $x12
+    ; Test that variables with multiple uses have correct liveness ranges
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    ; %0 used here and later
+    %3:gpr = ADD %0, %1
+    ; %3 used in next instruction
+    %4:gpr = MUL %3, %2
+    ; %0 used again here (should still be live)
+    %5:gpr = SUB %4, %0
+    ; %1 used again here
+    %6:gpr = ADD %5, %1
+    $x10 = COPY %6
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/live-variables-calls.mir b/llvm/test/CodeGen/RISCV/live-variables-calls.mir
new file mode 100644
index 0000000000000..6f80317dbf293
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/live-variables-calls.mir
@@ -0,0 +1,214 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv64 -run-pass=riscv-live-variables -verify-machineinstrs -o - %s | FileCheck %s
+#
+# Test live variable analysis with function calls and register clobbering
+# Function calls clobber caller-saved registers, which affects liveness
+
+--- |
+  declare i64 @external_func(i64, i64)
+  declare void @void_func(i64)
+
+  define i64 @test_call_simple(i64 %a, i64 %b) {
+  entry:
+    %result = call i64 @external_func(i64 %a, i64 %b)
+    ret i64 %result
+  }
+
+  define i64 @test_call_with_live_values(i64 %a, i64 %b, i64 %c) {
+  entry:
+    %sum1 = add i64 %a, %b
+    %result = call i64 @external_func(i64 %sum1, i64 %c)
+    ; %b is live across the call
+    %final = add i64 %result, %b
+    ret i64 %final
+  }
+
+  define i64 @test_multiple_calls(i64 %a, i64 %b) {
+  entry:
+    %r1 = call i64 @external_func(i64 %a, i64 %b)
+    call void @void_func(i64 %r1)
+    %r2 = call i64 @external_func(i64 %r1, i64 %b)
+    ret i64 %r2
+  }
+
+  define i64 @test_call_with_spill(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64 %g, i64 %h) {
+  entry:
+    %sum = add i64 %a, %b
+    %result = call i64 @external_func(i64 %sum, i64 %c)
+    ; Many values live across call - may require spilling
+    %t1 = add i64 %result, %d
+    %t2 = add i64 %t1, %e
+    %t3 = add i64 %t2, %f
+    %t4 = add i64 %t3, %g
+    %t5 = add i64 %t4, %h
+    ret i64 %t5
+  }
+...
+---
+name:            test_call_simple
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: test_call_simple
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: liveins: $x10, $x11
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    $x10 = COPY %0
+    $x11 = COPY %1
+    ; Call clobbers many registers per calling convention
+    PseudoCALL target-flags(riscv-call) @external_func, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10
+    %2:gpr = COPY $x10
+    $x10 = COPY %2
+    PseudoRET implicit $x10
+...
+---
+name:            test_call_with_live_values
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+  - { reg: '$x12', virtual-reg: '%2' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11, $x12
+    ; CHECK-LABEL: name: test_call_with_live_values
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: liveins: $x10, $x11, $x12
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    %3:gpr = ADD %0, %1
+    ; %1 must remain live across this call
+    $x10 = COPY %3
+    $x11 = COPY %2
+    PseudoCALL target-flags(riscv-call) @external_func, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10
+    %4:gpr = COPY $x10
+    ; %1 is used again here after the call
+    %5:gpr = ADD %4, %1
+    $x10 = COPY %5
+    PseudoRET implicit $x10
+...
+---
+name:            test_multiple_calls
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: test_multiple_calls
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: liveins: $x10, $x11
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+
+    ; First call
+    $x10 = COPY %0
+    $x11 = COPY %1
+    PseudoCALL target-flags(riscv-call) @external_func, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10
+    %2:gpr = COPY $x10
+
+    ; Second call (void)
+    $x10 = COPY %2
+    PseudoCALL target-flags(riscv-call) @void_func, csr_ilp32_lp64, implicit-def $x1, implicit $x10
+
+    ; Third call - %2 and %1 are both live here
+    $x10 = COPY %2
+    $x11 = COPY %1
+    PseudoCALL target-flags(riscv-call) @external_func, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10
+    %3:gpr = COPY $x10
+
+    $x10 = COPY %3
+    PseudoRET implicit $x10
+...
+---
+name:            test_call_with_spill
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+  - { id: 6, class: gpr }
+  - { id: 7, class: gpr }
+  - { id: 8, class: gpr }
+  - { id: 9, class: gpr }
+  - { id: 10, class: gpr }
+  - { id: 11, class: gpr }
+  - { id: 12, class: gpr }
+  - { id: 13, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+  - { reg: '$x12', virtual-reg: '%2' }
+  - { reg: '$x13', virtual-reg: '%3' }
+  - { reg: '$x14', virtual-reg: '%4' }
+  - { reg: '$x15', virtual-reg: '%5' }
+  - { reg: '$x16', virtual-reg: '%6' }
+  - { reg: '$x17', virtual-reg: '%7' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17
+    ; CHECK-LABEL: name: test_call_with_spill
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17
+    ; Many registers live across call - tests register pressure
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    %3:gpr = COPY $x13
+    %4:gpr = COPY $x14
+    %5:gpr = COPY $x15
+    %6:gpr = COPY $x16
+    %7:gpr = COPY $x17
+
+    %8:gpr = ADD %0, %1
+
+    ; Call with many live values - %3, %4, %5, %6, %7 all live across
+    $x10 = COPY %8
+    $x11 = COPY %2
+    PseudoCALL target-flags(riscv-call) @external_func, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10
+    %9:gpr = COPY $x10
+
+    ; All these values should have been kept live
+    %10:gpr = ADD %9, %3
+    %11:gpr = ADD %10, %4
+    %12:gpr = ADD %11, %5
+    %13:gpr = ADD %12, %6
+    %14:gpr = ADD %13, %7
+
+    $x10 = COPY %14
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir b/llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir
new file mode 100644
index 0000000000000..4e04de8a310a4
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir
@@ -0,0 +1,285 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv64 -run-pass=riscv-live-variables -verify-machineinstrs -o - %s | FileCheck %s
+#
+# Test live variable analysis edge cases and special scenarios
+# Including: dead code, unreachable blocks, critical edges, and complex phi nodes
+
+--- |
+  define i64 @test_dead_code(i64 %a, i64 %b) {
+  entry:
+    %dead = add i64 %a, %b
+    ret i64 %a
+  }
+
+  define i64 @test_critical_edge(i64 %a, i64 %b, i64 %c) {
+  entry:
+    %cmp1 = icmp sgt i64 %a, 0
+    br i1 %cmp1, label %then, label %check2
+
+  check2:
+    %cmp2 = icmp sgt i64 %b, 0
+    br i1 %cmp2, label %then, label %else
+
+  then:
+    %mul = mul i64 %a, %b
+    br label %end
+
+  else:
+    %sub = sub i64 %a, %c
+    br label %end
+
+  end:
+    %result = phi i64 [ %mul, %then ], [ %sub, %else ]
+    ret i64 %result
+  }
+
+  define i64 @test_complex_phi(i64 %a, i64 %b, i64 %c, i64 %d) {
+  entry:
+    %cmp1 = icmp sgt i64 %a, 0
+    br i1 %cmp1, label %path1, label %path2
+
+  path1:
+    %v1 = add i64 %a, %b
+    br label %merge
+
+  path2:
+    %cmp2 = icmp sgt i64 %c, 0
+    br i1 %cmp2, label %path2a, label %path2b
+
+  path2a:
+    %v2a = mul i64 %c, %d
+    br label %merge
+
+  path2b:
+    %v2b = sub i64 %c, %d
+    br label %merge
+
+  merge:
+    %result = phi i64 [ %v1, %path1 ], [ %v2a, %path2a ], [ %v2b, %path2b ]
+    ret i64 %result
+  }
+
+  define i64 @test_use_after_def(i64 %a) {
+  entry:
+    %v1 = add i64 %a, 1
+    %v2 = add i64 %v1, 2
+    %v3 = add i64 %v2, 3
+    %v4 = add i64 %v1, %v3
+    ret i64 %v4
+  }
+
+  define i64 @test_implicit_defs(i64 %a, i64 %b) {
+  entry:
+    %div = sdiv i64 %a, %b
+    %rem = srem i64 %a, %b
+    %sum = add i64 %div, %rem
+    ret i64 %sum
+  }
+...
+---
+name:            test_dead_code
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: test_dead_code
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: liveins: $x10, $x11
+    ; %2 is dead - never used, should not affect liveness of inputs
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    ; Dead instruction - result never used
+    %2:gpr = ADD %0, %1
+    ; Only %0 should be live here
+    $x10 = COPY %0
+    PseudoRET implicit $x10
+...
+---
+name:            test_critical_edge
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+  - { id: 6, class: gpr }
+  - { id: 7, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+  - { reg: '$x12', virtual-reg: '%2' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11, $x12
+    ; CHECK-LABEL: name: test_critical_edge
+    ; CHECK: bb.0.entry:
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    %3:gpr = SLTI %0, 1
+    BEQ %3, $x0, %bb.2
+
+  bb.1.check2:
+    ; CHECK: bb.1.check2:
+    ; %0, %1, %2 should all be live-in
+
+    %4:gpr = SLTI %1, 1
+    BEQ %4, $x0, %bb.3
+
+  bb.2.then:
+    ; CHECK: bb.2.then:
+    ; %0, %1 should be live-in (used in mul)
+
+    %5:gpr = MUL %0, %1
+    PseudoBR %bb.4
+
+  bb.3.else:
+    ; CHECK: bb.3.else:
+    ; %0, %2 should be live-in (used in sub)
+
+    %6:gpr = SUB %0, %2
+    PseudoBR %bb.4
+
+  bb.4.end:
+    ; CHECK: bb.4.end:
+    ; Either %5 or %6 should be live-in
+
+    %7:gpr = PHI %5, %bb.2, %6, %bb.3
+    $x10 = COPY %7
+    PseudoRET implicit $x10
+...
+---
+name:            test_complex_phi
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+  - { id: 6, class: gpr }
+  - { id: 7, class: gpr }
+  - { id: 8, class: gpr }
+  - { id: 9, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+  - { reg: '$x12', virtual-reg: '%2' }
+  - { reg: '$x13', virtual-reg: '%3' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11, $x12, $x13
+    ; CHECK-LABEL: name: test_complex_phi
+    ; CHECK: bb.0.entry:
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    %3:gpr = COPY $x13
+    %4:gpr = SLTI %0, 1
+    BEQ %4, $x0, %bb.2
+
+  bb.1.path1:
+    ; CHECK: bb.1.path1:
+
+    %5:gpr = ADD %0, %1
+    PseudoBR %bb.5
+
+  bb.2.path2:
+    ; CHECK: bb.2.path2:
+    ; %2, %3 should be live-in
+
+    %6:gpr = SLTI %2, 1
+    BEQ %6, $x0, %bb.4
+
+  bb.3.path2a:
+    ; CHECK: bb.3.path2a:
+
+    %7:gpr = MUL %2, %3
+    PseudoBR %bb.5
+
+  bb.4.path2b:
+    ; CHECK: bb.4.path2b:
+
+    %8:gpr = SUB %2, %3
+    PseudoBR %bb.5
+
+  bb.5.merge:
+    ; CHECK: bb.5.merge:
+    ; One of %5, %7, %8 should be live-in
+
+    %9:gpr = PHI %5, %bb.1, %7, %bb.3, %8, %bb.4
+    $x10 = COPY %9
+    PseudoRET implicit $x10
+...
+---
+name:            test_use_after_def
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: test_use_after_def
+    ; CHECK: bb.0.entry:
+    ; Test that %1 remains live even after being used in %2
+
+    %0:gpr = COPY $x10
+    %1:gpr = ADDI %0, 1
+    %2:gpr = ADDI %1, 2
+    %3:gpr = ADDI %2, 3
+    ; %1 used again here - should have been kept live
+    %4:gpr = ADD %1, %3
+    $x10 = COPY %4
+    PseudoRET implicit $x10
+...
+---
+name:            test_implicit_defs
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: test_implicit_defs
+    ; CHECK: bb.0.entry:
+    ; Test handling of division which may have implicit defs/uses
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = DIV %0, %1
+    %3:gpr = REM %0, %1
+    %4:gpr = ADD %2, %3
+    $x10 = COPY %4
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/live-variables-loops.mir b/llvm/test/CodeGen/RISCV/live-variables-loops.mir
new file mode 100644
index 0000000000000..05e24b33a1131
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/live-variables-loops.mir
@@ -0,0 +1,238 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv64 -run-pass=riscv-live-variables -verify-machineinstrs -o - %s | FileCheck %s
+#
+# Test live variable analysis with loops and backward edges
+# Loops create interesting liveness patterns with phi nodes and variables
+# that are live across backedges
+
+--- |
+  define i64 @test_simple_loop(i64 %n) {
+  entry:
+    br label %loop
+
+  loop:
+    %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+    %sum = phi i64 [ 0, %entry ], [ %sum.next, %loop ]
+    %sum.next = add i64 %sum, %i
+    %i.next = add i64 %i, 1
+    %cmp = icmp slt i64 %i.next, %n
+    br i1 %cmp, label %loop, label %exit
+
+  exit:
+    ret i64 %sum.next
+  }
+
+  define i64 @test_nested_loop(i64 %n, i64 %m) {
+  entry:
+    br label %outer.loop
+
+  outer.loop:
+    %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
+    %outer.sum = phi i64 [ 0, %entry ], [ %new.outer.sum, %outer.latch ]
+    br label %inner.loop
+
+  inner.loop:
+    %j = phi i64 [ 0, %outer.loop ], [ %j.next, %inner.loop ]
+    %inner.sum = phi i64 [ 0, %outer.loop ], [ %inner.sum.next, %inner.loop ]
+    %prod = mul i64 %i, %j
+    %inner.sum.next = add i64 %inner.sum, %prod
+    %j.next = add i64 %j, 1
+    %inner.cmp = icmp slt i64 %j.next, %m
+    br i1 %inner.cmp, label %inner.loop, label %outer.latch
+
+  outer.latch:
+    %new.outer.sum = add i64 %outer.sum, %inner.sum.next
+    %i.next = add i64 %i, 1
+    %outer.cmp = icmp slt i64 %i.next, %n
+    br i1 %outer.cmp, label %outer.loop, label %exit
+
+  exit:
+    ret i64 %new.outer.sum
+  }
+
+  define i64 @test_loop_with_invariant(i64 %n, i64 %k) {
+  entry:
+    %double_k = mul i64 %k, 2
+    br label %loop
+
+  loop:
+    %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+    %sum = phi i64 [ 0, %entry ], [ %sum.next, %loop ]
+    ; double_k is loop-invariant and should be live throughout the loop
+    %scaled = mul i64 %i, %double_k
+    %sum.next = add i64 %sum, %scaled
+    %i.next = add i64 %i, 1
+    %cmp = icmp slt i64 %i.next, %n
+    br i1 %cmp, label %loop, label %exit
+
+  exit:
+    ret i64 %sum.next
+  }
+...
+---
+name:            test_simple_loop
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+  - { id: 6, class: gpr }
+  - { id: 7, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: test_simple_loop
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: successors
+    ; CHECK-NEXT: liveins: $x10
+
+    %0:gpr = COPY $x10
+    %1:gpr = ADDI $x0, 0
+    %2:gpr = ADDI $x0, 0
+    PseudoBR %bb.1
+
+  bb.1.loop:
+    ; CHECK: bb.1.loop:
+    ; %0 should be live-in (used in comparison)
+    ; %1 and %2 should be live-in from backedge or entry
+
+    %3:gpr = PHI %1, %bb.0, %5, %bb.1
+    %4:gpr = PHI %2, %bb.0, %6, %bb.1
+    %6:gpr = ADD %4, %3
+    %5:gpr = ADDI %3, 1
+    %7:gpr = SLT %5, %0
+    BNE %7, $x0, %bb.1
+
+  bb.2.exit:
+    ; CHECK: bb.2.exit:
+    ; %6 should be live-in
+
+    $x10 = COPY %6
+    PseudoRET implicit $x10
+...
+---
+name:            test_nested_loop
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+  - { id: 6, class: gpr }
+  - { id: 7, class: gpr }
+  - { id: 8, class: gpr }
+  - { id: 9, class: gpr }
+  - { id: 10, class: gpr }
+  - { id: 11, class: gpr }
+  - { id: 12, class: gpr }
+  - { id: 13, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: test_nested_loop
+    ; CHECK: bb.0.entry:
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = ADDI $x0, 0
+    %3:gpr = ADDI $x0, 0
+    PseudoBR %bb.1
+
+  bb.1.outer.loop:
+    ; CHECK: bb.1.outer.loop:
+    ; %0 and %1 should be live-in (loop bounds)
+
+    %4:gpr = PHI %2, %bb.0, %12, %bb.3
+    %5:gpr = PHI %3, %bb.0, %11, %bb.3
+    %6:gpr = ADDI $x0, 0
+    %7:gpr = ADDI $x0, 0
+    PseudoBR %bb.2
+
+  bb.2.inner.loop:
+    ; CHECK: bb.2.inner.loop:
+    ; %1, %4, %5 should be live-in
+
+    %8:gpr = PHI %6, %bb.1, %13, %bb.2
+    %9:gpr = PHI %7, %bb.1, %10, %bb.2
+    %10:gpr = MUL %4, %8
+    %10:gpr = ADD %9, %10
+    %13:gpr = ADDI %8, 1
+    %14:gpr = SLT %13, %1
+    BNE %14, $x0, %bb.2
+
+  bb.3.outer.latch:
+    ; CHECK: bb.3.outer.latch:
+    ; %0, %5, %10 should be live-in
+
+    %11:gpr = ADD %5, %10
+    %12:gpr = ADDI %4, 1
+    %15:gpr = SLT %12, %0
+    BNE %15, $x0, %bb.1
+
+  bb.4.exit:
+    ; CHECK: bb.4.exit:
+
+    $x10 = COPY %11
+    PseudoRET implicit $x10
+...
+---
+name:            test_loop_with_invariant
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+  - { id: 6, class: gpr }
+  - { id: 7, class: gpr }
+  - { id: 8, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: test_loop_with_invariant
+    ; CHECK: bb.0.entry:
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = SLLI %1, 1
+    %3:gpr = ADDI $x0, 0
+    %4:gpr = ADDI $x0, 0
+    PseudoBR %bb.1
+
+  bb.1.loop:
+    ; CHECK: bb.1.loop:
+    ; %0 and %2 should be live-in (loop bound and invariant)
+    ; %2 is computed before loop but used in every iteration
+
+    %5:gpr = PHI %3, %bb.0, %7, %bb.1
+    %6:gpr = PHI %4, %bb.0, %8, %bb.1
+    %9:gpr = MUL %5, %2
+    %8:gpr = ADD %6, %9
+    %7:gpr = ADDI %5, 1
+    %10:gpr = SLT %7, %0
+    BNE %10, $x0, %bb.1
+
+  bb.2.exit:
+    ; CHECK: bb.2.exit:
+
+    $x10 = COPY %8
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/live-variables-rv64.mir b/llvm/test/CodeGen/RISCV/live-variables-rv64.mir
new file mode 100644
index 0000000000000..5b396373a60f4
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/live-variables-rv64.mir
@@ -0,0 +1,188 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv64 -run-pass=riscv-live-variables -verify-machineinstrs -o - %s | FileCheck %s
+#
+# Test live variable analysis for RV64-specific scenarios
+# This includes 64-bit operations, wide registers, and RV64-specific instructions
+
+--- |
+  define i64 @test_64bit_ops(i64 %a, i64 %b) {
+  entry:
+    %shl = shl i64 %a, 32
+    %or = or i64 %shl, %b
+    ret i64 %or
+  }
+
+  define i64 @test_word_ops(i64 %a, i64 %b) {
+  entry:
+    %trunc_a = trunc i64 %a to i32
+    %trunc_b = trunc i64 %b to i32
+    %add = add i32 %trunc_a, %trunc_b
+    %ext = sext i32 %add to i64
+    ret i64 %ext
+  }
+
+  define i64 @test_mixed_width(i64 %a, i32 %b) {
+  entry:
+    %ext_b = sext i32 %b to i64
+    %mul = mul i64 %a, %ext_b
+    %trunc = trunc i64 %mul to i32
+    %final = sext i32 %trunc to i64
+    ret i64 %final
+  }
+
+  define double @test_float_64(double %a, double %b, i64 %selector) {
+  entry:
+    %cmp = icmp eq i64 %selector, 0
+    br i1 %cmp, label %then, label %else
+
+  then:
+    %add = fadd double %a, %b
+    br label %end
+
+  else:
+    %mul = fmul double %a, %b
+    br label %end
+
+  end:
+    %result = phi double [ %add, %then ], [ %mul, %else ]
+    ret double %result
+  }
+...
+---
+name:            test_64bit_ops
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: test_64bit_ops
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: liveins: $x10, $x11
+    ; Test 64-bit shift and or operations
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    ; SLLI for 64-bit shift (RV64-specific immediate range)
+    %2:gpr = SLLI %0, 32
+    %3:gpr = OR %2, %1
+    $x10 = COPY %3
+    PseudoRET implicit $x10
+...
+---
+name:            test_word_ops
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: test_word_ops
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: liveins: $x10, $x11
+    ; Test RV64 W-suffix instructions (32-bit ops on 64-bit regs)
+
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    ; ADDW is RV64-specific: 32-bit add with sign-extension
+    %2:gpr = ADDW %0, %1
+    $x10 = COPY %2
+    PseudoRET implicit $x10
+...
+---
+name:            test_mixed_width
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11_w', virtual-reg: '%1' }
+body:             |
+  bb.0.entry:
+    liveins: $x10, $x11_w
+    ; CHECK-LABEL: name: test_mixed_width
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: liveins: $x10, $x11_w
+    ; Test mixed 32/64-bit operations
+
+    %0:gpr = COPY $x10
+    ; Sign-extend 32-bit value to 64-bit
+    %1:gpr = COPY $x11_w
+    %2:gpr = ADDIW %1, 0
+    %3:gpr = MUL %0, %2
+    ; Extract lower 32 bits and sign-extend
+    %4:gpr = ADDIW %3, 0
+    $x10 = COPY %4
+    PseudoRET implicit $x10
+...
+---
+name:            test_float_64
+alignment:       4
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: fpr64 }
+  - { id: 1, class: fpr64 }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: fpr64 }
+  - { id: 5, class: fpr64 }
+  - { id: 6, class: fpr64 }
+liveins:
+  - { reg: '$f10_d', virtual-reg: '%0' }
+  - { reg: '$f11_d', virtual-reg: '%1' }
+  - { reg: '$x10', virtual-reg: '%2' }
+body:             |
+  bb.0.entry:
+    liveins: $f10_d, $f11_d, $x10
+    ; CHECK-LABEL: name: test_float_64
+    ; CHECK: bb.0.entry:
+    ; CHECK-NEXT: successors
+    ; CHECK-NEXT: liveins: $f10_d, $f11_d, $x10
+    ; Test 64-bit floating point register liveness
+
+    %0:fpr64 = COPY $f10_d
+    %1:fpr64 = COPY $f11_d
+    %2:gpr = COPY $x10
+    %3:gpr = ADDI $x0, 0
+    BNE %2, %3, %bb.2
+
+  bb.1.then:
+    ; CHECK: bb.1.then:
+    ; %0 and %1 should be live-in (FP registers)
+
+    %4:fpr64 = FADD_D %0, %1, 7
+    PseudoBR %bb.3
+
+  bb.2.else:
+    ; CHECK: bb.2.else:
+    ; %0 and %1 should be live-in
+
+    %5:fpr64 = FMUL_D %0, %1, 7
+    PseudoBR %bb.3
+
+  bb.3.end:
+    ; CHECK: bb.3.end:
+    ; Either %4 or %5 should be live-in
+
+    %6:fpr64 = PHI %4, %bb.1, %5, %bb.2
+    $f10_d = COPY %6
+    PseudoRET implicit $f10_d
+...

>From 0120ce4a667d12f39599f74d0fa318d4ac3400de Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Mon, 10 Nov 2025 20:49:02 -0800
Subject: [PATCH 03/32] WIP genset calculation

---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp  | 47 +++++++++----------
 .../CodeGen/RISCV/live-variables-basic.mir    | 10 ++++
 2 files changed, 32 insertions(+), 25 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index b8eb6614470b9..e044da47491fc 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -22,10 +22,7 @@
 #include "RISCVInstrInfo.h"
 #include "RISCVSubtarget.h"
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DepthFirstIterator.h"
 #include "llvm/ADT/PostOrderIterator.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
@@ -59,7 +56,7 @@ struct LivenessInfo {
   std::set<Register> LiveOut;
 
   /// Registers that are defined in this block
-  std::set<Register> Def;
+  std::set<Register> Gen;
 
   /// Registers that are used in this block before being defined (if at all).
   std::set<Register> Use;
@@ -174,29 +171,16 @@ void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
     if (!isTrackableRegister(Reg, TRI, MRI))
       continue;
 
-    if (MO.isDef()) {
-      // This is a definition
-      Info.Def.insert(Reg);
-
-      // Also handle sub-registers for physical registers
-      if (Reg.isPhysical()) {
-        for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
-             SubRegs.isValid(); ++SubRegs) {
-          Info.Def.insert(*SubRegs);
-        }
-      }
-    }
-
     if (MO.isUse()) {
       // This is a use - only add to Use set if not already defined in this block
-      if (Info.Def.find(Reg) == Info.Def.end()) {
+      if (Info.Gen.find(Reg) == Info.Gen.end()) {
         Info.Use.insert(Reg);
 
         // Also handle sub-registers for physical registers
         if (Reg.isPhysical()) {
           for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
                SubRegs.isValid(); ++SubRegs) {
-            if (Info.Def.find(*SubRegs) == Info.Def.end()) {
+            if (Info.Gen.find(*SubRegs) == Info.Gen.end()) {
               Info.Use.insert(*SubRegs);
             }
           }
@@ -206,10 +190,23 @@ void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
 
     // Handle implicit operands (like condition codes, stack pointer updates)
     if (MO.isImplicit() && MO.isUse() && Reg.isPhysical()) {
-      if (Info.Def.find(Reg) == Info.Def.end()) {
+      if (Info.Gen.find(Reg) == Info.Gen.end()) {
         Info.Use.insert(Reg);
       }
     }
+
+    if (MO.isDef()) {
+      // This is a definition
+      Info.Gen.insert(Reg);
+
+      // Also handle sub-registers for physical registers
+      if (Reg.isPhysical()) {
+        for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
+             SubRegs.isValid(); ++SubRegs) {
+          Info.Gen.insert(*SubRegs);
+        }
+      }
+    }
   }
 
   // Handle RegMasks (from calls) - they kill all non-preserved registers
@@ -225,7 +222,7 @@ void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
 
         // Mark as defined (clobbered)
         if (isTrackableRegister(Register(PhysReg), TRI, MRI)) {
-          Info.Def.insert(Register(PhysReg));
+          Info.Gen.insert(Register(PhysReg));
         }
       }
     }
@@ -238,7 +235,7 @@ void RISCVLiveVariables::computeLocalLiveness(MachineFunction &MF) {
   // Process each basic block
   for (MachineBasicBlock &MBB : MF) {
     LivenessInfo &Info = BlockLiveness[&MBB];
-    Info.Def.clear();
+    Info.Gen.clear();
     Info.Use.clear();
 
     // Process instructions in forward order to build Use and Def sets
@@ -267,7 +264,7 @@ void RISCVLiveVariables::computeGlobalLiveness(MachineFunction &MF) {
   LLVM_DEBUG(dbgs() << "Computing global liveness (fixed-point iteration)\n");
 
   bool Changed = true;
-  unsigned Iterations = 0;
+  [[maybe_unused]] unsigned Iterations = 0;
 
   // Iterate until we reach a fixed point
   // Live-out[B] = Union of Live-in[S] for all successors S of B
@@ -296,7 +293,7 @@ void RISCVLiveVariables::computeGlobalLiveness(MachineFunction &MF) {
       std::set<Register> NewLiveIn = Info.Use;
 
       for (Register Reg : Info.LiveOut) {
-        if (Info.Def.find(Reg) == Info.Def.end()) {
+        if (Info.Gen.find(Reg) == Info.Gen.end()) {
           NewLiveIn.insert(Reg);
         }
       }
@@ -420,7 +417,7 @@ void RISCVLiveVariables::print(raw_ostream &OS, const Module *M) const {
     OS << "}\n";
 
     OS << "  Def:      { ";
-    for (Register Reg : Info.Def) {
+    for (Register Reg : Info.Gen) {
       OS << printReg(Reg, TRI) << " ";
     }
     OS << "}\n\n";
diff --git a/llvm/test/CodeGen/RISCV/live-variables-basic.mir b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
index 741a8eafa1c27..2695f0bc15c02 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-basic.mir
+++ b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
@@ -36,6 +36,16 @@
     %t4 = add i64 %t3, %b
     ret i64 %t4
   }
+
+  define i64 @test_gen_kill(i64 %a, i64 %b, i64 %c) {
+  entry:
+    %t1 = add i64 %a, %b
+    %t2 = mul i64 %t1, %c
+    %t3 = sub i64 %t2, %a
+    %t4 = add i64 %t3, %b
+    ret i64 %t4
+  }
+
 ...
 ---
 name:            test_simple_add

>From bf78489fc7bfada67e032efbc74fecbe76026d15 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Fri, 14 Nov 2025 20:03:46 -0800
Subject: [PATCH 04/32] Verify liveness is working

---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp | 7 +++++++
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp | 4 ++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index e044da47491fc..3c78afaa9b2db 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -320,6 +320,13 @@ void RISCVLiveVariables::computeGlobalLiveness(MachineFunction &MF) {
     const MachineBasicBlock &EntryBB = MF.front();
     NumLiveRegsAtEntry += BlockLiveness[&EntryBB].LiveIn.size();
   }
+
+  for (auto &BB : MF) {
+    auto &computedLivein = BlockLiveness[&BB].LiveIn;
+    for (auto &LI : BB.getLiveIns()) {
+      assert(0 && computedLivein.count(LI.PhysReg));
+    }
+  }
 }
 
 bool RISCVLiveVariables::isLiveAt(Register Reg,
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index bbb6be2cf5d30..f5c59785f065e 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -584,7 +584,6 @@ void RISCVPassConfig::addPreEmitPass() {
   addPass(createRISCVIndirectBranchTrackingPass());
   addPass(&BranchRelaxationPassID);
   addPass(createRISCVMakeCompressibleOptPass());
-  addPass(createRISCVLiveVariablesPass());
 }
 
 void RISCVPassConfig::addPreEmitPass2() {
@@ -622,7 +621,6 @@ void RISCVPassConfig::addMachineSSAOptimization() {
   TargetPassConfig::addMachineSSAOptimization();
 
   if (TM->getTargetTriple().isRISCV64()) {
-    addPass(createRISCVLiveVariablesPass());
     addPass(createRISCVOptWInstrsPass());
   }
 }
@@ -655,6 +653,8 @@ void RISCVPassConfig::addPostRegAlloc() {
   if (TM->getOptLevel() != CodeGenOptLevel::None &&
       EnableRedundantCopyElimination)
     addPass(createRISCVRedundantCopyEliminationPass());
+
+  addPass(createRISCVLiveVariablesPass());
 }
 
 bool RISCVPassConfig::addILPOpts() {

>From a8ab83c2ac202e0335e7795e673b7d18cfbd92e2 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sat, 15 Nov 2025 04:45:49 -0800
Subject: [PATCH 05/32] Add flag for live variable analysis

Add an mir test
---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp  | 55 +++++++------
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp  |  8 +-
 .../CodeGen/RISCV/live-variables-basic.mir    |  2 +
 .../CodeGen/RISCV/live-variables-calls.mir    |  2 +
 .../CodeGen/RISCV/machine-live-variables.mir  | 79 +++++++++++++++++++
 5 files changed, 123 insertions(+), 23 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/machine-live-variables.mir

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index 3c78afaa9b2db..f7927b748f4a4 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -31,6 +31,7 @@
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 #include <set>
 
@@ -99,6 +100,7 @@ class RISCVLiveVariables : public MachineFunctionPass {
   /// Print liveness information for debugging
   void print(raw_ostream &OS, const Module *M = nullptr) const override;
 
+  void verifyLiveness(MachineFunction &MF) const;
 private:
   /// Compute local liveness information (Use and Def sets) for each block
   void computeLocalLiveness(MachineFunction &MF);
@@ -160,7 +162,7 @@ bool RISCVLiveVariables::isTrackableRegister(
 void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
                                              LivenessInfo &Info,
                                              const TargetRegisterInfo *TRI) {
-  // Process all operands
+  std::vector<Register> GenVec;
   for (const MachineOperand &MO : MI.operands()) {
     if (!MO.isReg() || !MO.getReg())
       continue;
@@ -195,16 +197,16 @@ void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
       }
     }
 
-    if (MO.isDef()) {
-      // This is a definition
-      Info.Gen.insert(Reg);
+    if (MO.isDef()) // Collect defs for later processing.
+      GenVec.push_back(Reg);
+  }
 
-      // Also handle sub-registers for physical registers
-      if (Reg.isPhysical()) {
-        for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
-             SubRegs.isValid(); ++SubRegs) {
-          Info.Gen.insert(*SubRegs);
-        }
+  for (auto Reg : GenVec) {
+    Info.Gen.insert(Reg);
+    if (Reg.isPhysical()) {
+      for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
+                SubRegs.isValid(); ++SubRegs) {
+            Info.Gen.insert(*SubRegs);
       }
     }
   }
@@ -253,7 +255,7 @@ void RISCVLiveVariables::computeLocalLiveness(MachineFunction &MF) {
       for (Register Reg : Info.Use)
         dbgs() << printReg(Reg, TRI) << " ";
       dbgs() << "\n  Def: ";
-      for (Register Reg : Info.Def)
+      for (Register Reg : Info.Gen)
         dbgs() << printReg(Reg, TRI) << " ";
       dbgs() << "\n";
     });
@@ -273,7 +275,7 @@ void RISCVLiveVariables::computeGlobalLiveness(MachineFunction &MF) {
     Changed = false;
     ++Iterations;
 
-    // Process blocks in reverse post-order for better convergence
+    // Process blocks in **post-order** for better convergence
     ReversePostOrderTraversal<MachineFunction *> RPOT(&MF);
 
     for (MachineBasicBlock *MBB : RPOT) {
@@ -320,13 +322,6 @@ void RISCVLiveVariables::computeGlobalLiveness(MachineFunction &MF) {
     const MachineBasicBlock &EntryBB = MF.front();
     NumLiveRegsAtEntry += BlockLiveness[&EntryBB].LiveIn.size();
   }
-
-  for (auto &BB : MF) {
-    auto &computedLivein = BlockLiveness[&BB].LiveIn;
-    for (auto &LI : BB.getLiveIns()) {
-      assert(0 && computedLivein.count(LI.PhysReg));
-    }
-  }
 }
 
 bool RISCVLiveVariables::isLiveAt(Register Reg,
@@ -355,8 +350,25 @@ bool RISCVLiveVariables::isLiveAt(Register Reg,
   return false;
 }
 
+void RISCVLiveVariables::verifyLiveness(MachineFunction &MF) const {
+  for (auto &BB : MF) {
+    auto BBLiveness = BlockLiveness.find(&BB);
+    assert(BBLiveness != BlockLiveness.end() && "Missing Liveness");
+    auto &ComputedLivein = BBLiveness->second.LiveIn;
+    for (auto &LI : BB.getLiveIns()) {
+      if (!ComputedLivein.count(LI.PhysReg)) {
+        LLVM_DEBUG(dbgs() << "Warning: Live-in register "
+                          << printReg(LI.PhysReg, TRI)
+                          << " missing from computed live-in set of block "
+                          << BB.getName() << "\n");
+        llvm_unreachable("Computed live-in set is inconsistent with MBB.");
+      }
+    }
+  }
+}
+
 bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
-  if (skipFunction(MF.getFunction()))
+  if (skipFunction(MF.getFunction()) || MF.empty())
     return false;
 
   const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
@@ -373,8 +385,6 @@ bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
 
   LLVM_DEBUG(dbgs() << "***** RISC-V Live Variable Analysis *****\n");
   LLVM_DEBUG(dbgs() << "Function: " << MF.getName() << "\n");
-  LLVM_DEBUG(dbgs() << "Target: RV" << (Subtarget.is64Bit() ? "64" : "32")
-                    << "\n");
 
   // Clear any previous analysis
   BlockLiveness.clear();
@@ -390,6 +400,7 @@ bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
     print(dbgs());
   });
 
+  verifyLiveness(MF);
   // This is an analysis pass, it doesn't modify the function
   return false;
 }
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index f5c59785f065e..9611920957ab4 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -109,6 +109,11 @@ static cl::opt<bool> EnableCFIInstrInserter(
     cl::desc("Enable CFI Instruction Inserter for RISC-V"), cl::init(false),
     cl::Hidden);
 
+static cl::opt<bool> EnableRISCVLiveVariables(
+    "riscv-live-variables",
+    cl::desc("Enable Live Variable Analysis for RISC-V"), cl::init(false),
+    cl::Hidden);
+
 static cl::opt<bool>
     EnableSelectOpt("riscv-select-opt", cl::Hidden,
                     cl::desc("Enable select to branch optimizations"),
@@ -654,7 +659,8 @@ void RISCVPassConfig::addPostRegAlloc() {
       EnableRedundantCopyElimination)
     addPass(createRISCVRedundantCopyEliminationPass());
 
-  addPass(createRISCVLiveVariablesPass());
+  if (EnableRISCVLiveVariables)
+    addPass(createRISCVLiveVariablesPass());
 }
 
 bool RISCVPassConfig::addILPOpts() {
diff --git a/llvm/test/CodeGen/RISCV/live-variables-basic.mir b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
index 2695f0bc15c02..3339b04602953 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-basic.mir
+++ b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
@@ -3,6 +3,8 @@
 #
 # Test basic live variable analysis with simple control flow and basic blocks
 
+# REQUIRES: Assertions
+
 --- |
   define i64 @test_simple_add(i64 %a, i64 %b) {
   entry:
diff --git a/llvm/test/CodeGen/RISCV/live-variables-calls.mir b/llvm/test/CodeGen/RISCV/live-variables-calls.mir
index 6f80317dbf293..2a2738eaa3bad 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-calls.mir
+++ b/llvm/test/CodeGen/RISCV/live-variables-calls.mir
@@ -4,6 +4,8 @@
 # Test live variable analysis with function calls and register clobbering
 # Function calls clobber caller-saved registers, which affects liveness
 
+# REQUIRES: Assertions
+
 --- |
   declare i64 @external_func(i64, i64)
   declare void @void_func(i64)
diff --git a/llvm/test/CodeGen/RISCV/machine-live-variables.mir b/llvm/test/CodeGen/RISCV/machine-live-variables.mir
new file mode 100644
index 0000000000000..734184964f50c
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/machine-live-variables.mir
@@ -0,0 +1,79 @@
+# RUN: llc -mtriple=riscv64 -verify-machineinstrs -run-pass=riscv-live-variables -debug < %s | FileCheck %s
+
+# REQUIRES: asserts
+
+;CHECK: Block:  (Number: 1)
+;CHECK:   Live-In:  { }
+;CHECK:   Live-Out: { }
+;CHECK:   Use:      { }
+;CHECK:   Def:      { $x10 $x11 $x12 $x13 $x14 $x15 $x16 $x10_h $x11_h $x12_h $x13_h $x14_h $x15_h $x16_h $x10_w $x11_w $x12_w $x13_w $x14_w $x15_w $x16_w }
+;CHECK: 
+;CHECK: Block:  (Number: 0)
+;CHECK:   Live-In:  { $x11 $x12 $x13 $x14 $x15 $x16 $x17 $x11_h $x12_h $x13_h $x14_h $x15_h $x16_h $x17_h $x11_w $x12_w $x13_w $x14_w $x15_w $x16_w $x17_w }
+;CHECK:   Live-Out: { }
+;CHECK:   Use:      { $x11 $x12 $x13 $x14 $x15 $x16 $x17 $x11_h $x12_h $x13_h $x14_h $x15_h $x16_h $x17_h $x11_w $x12_w $x13_w $x14_w $x15_w $x16_w $x17_w }
+;CHECK:   Def:      { $x10 $x11 $x12 $x10_h $x11_h $x12_h $x10_w $x11_w $x12_w }
+
+--- |
+
+  source_filename = "liveness-varargs.ll"
+  target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
+  target triple = "riscv64"
+
+  declare void @notdead(ptr)
+
+  define i32 @va1(ptr %fmt, ...) {
+    %va = alloca ptr, align 8
+    call void @llvm.va_start.p0(ptr %va)
+    %argp.cur = load ptr, ptr %va, align 4
+    %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4
+    store ptr %argp.next, ptr %va, align 4
+    %1 = load i32, ptr %argp.cur, align 4
+    call void @llvm.va_end.p0(ptr %va)
+    ret i32 %1
+  }
+
+  declare void @llvm.va_start.p0(ptr) #1
+
+  declare void @llvm.va_end.p0(ptr) #1
+
+  declare void @llvm.va_copy.p0(ptr, ptr) #1
+
+  attributes #0 = { nounwind }
+  attributes #1 = { nocallback nofree nosync nounwind willreturn }
+...
+
+---
+name: va1
+tracksRegLiveness: true
+noVRegs: false
+fixedStack:
+  - { id: 0, offset: 8, size: 8, alignment: 8, isImmutable: false }
+  - { id: 1, offset: 56, size: 56, alignment: 8, isImmutable: true }
+  - { id: 2, offset: 64, size: 8, alignment: 16, isImmutable: true }
+stack:
+  - { id: 0, name: va, size: 2, alignment: 2, stack-id: default }
+
+body: |
+  bb.0:
+    liveins: $x11, $x12, $x13, $x14, $x15, $x16, $x17
+    SD killed renamable $x11, %fixed-stack.1, 0 :: (store (s64) into %fixed-stack.1)
+    SD killed renamable $x12, %fixed-stack.1, 8 :: (store (s64) into %fixed-stack.1 + 8)
+    SD killed renamable $x13, %fixed-stack.1, 16 :: (store (s64) into %fixed-stack.1 + 16)
+    SD killed renamable $x14, %fixed-stack.1, 24 :: (store (s64) into %fixed-stack.1 + 24)
+    renamable $x10 = ADDI %stack.0.va, 0
+    renamable $x11 = ADDI %fixed-stack.1, 0
+    SD killed renamable $x11, %stack.0.va, 0 :: (store (s64) into %ir.va)
+    renamable $x10 = LW killed renamable $x10, 4 :: (dereferenceable load (s32) from %ir.va + 4)
+    renamable $x11 = LWU %stack.0.va, 0 :: (dereferenceable load (s32) from %ir.va)
+    SD killed renamable $x15, %fixed-stack.1, 32 :: (store (s64) into %fixed-stack.1 + 32)
+    SD killed renamable $x16, %fixed-stack.1, 40 :: (store (s64) into %fixed-stack.1 + 40)
+    SD killed renamable $x17, %fixed-stack.1, 48 :: (store (s64) into %fixed-stack.1 + 48)
+    renamable $x10 = SLLI killed renamable $x10, 32
+    renamable $x10 = OR killed renamable $x10, killed renamable $x11
+    renamable $x11 = nuw nusw inbounds ADDI renamable $x10, 4
+    renamable $x12 = SRLI renamable $x11, 32
+    SW killed renamable $x11, %stack.0.va, 0 :: (store (s32) into %ir.va)
+    SW killed renamable $x12, %stack.0.va, 4 :: (store (s32) into %ir.va + 4)
+    renamable $x10 = LW killed renamable $x10, 0 :: (load (s32) from %ir.argp.cur)
+    PseudoRET implicit $x10

>From 06bdab04d9fdb05d62a4c41a59865c01532ea33c Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sat, 15 Nov 2025 04:46:45 -0800
Subject: [PATCH 06/32] clang format

---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp  | 15 ++++++-------
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp  |  2 +-
 .../CodeGen/RISCV/machine-live-variables.mir  | 21 ++++++++-----------
 3 files changed, 18 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index f7927b748f4a4..5a9f192ad23ce 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -101,6 +101,7 @@ class RISCVLiveVariables : public MachineFunctionPass {
   void print(raw_ostream &OS, const Module *M = nullptr) const override;
 
   void verifyLiveness(MachineFunction &MF) const;
+
 private:
   /// Compute local liveness information (Use and Def sets) for each block
   void computeLocalLiveness(MachineFunction &MF);
@@ -160,8 +161,8 @@ bool RISCVLiveVariables::isTrackableRegister(
 }
 
 void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
-                                             LivenessInfo &Info,
-                                             const TargetRegisterInfo *TRI) {
+                                            LivenessInfo &Info,
+                                            const TargetRegisterInfo *TRI) {
   std::vector<Register> GenVec;
   for (const MachineOperand &MO : MI.operands()) {
     if (!MO.isReg() || !MO.getReg())
@@ -174,7 +175,8 @@ void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
       continue;
 
     if (MO.isUse()) {
-      // This is a use - only add to Use set if not already defined in this block
+      // This is a use - only add to Use set if not already defined in this
+      // block
       if (Info.Gen.find(Reg) == Info.Gen.end()) {
         Info.Use.insert(Reg);
 
@@ -205,8 +207,8 @@ void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
     Info.Gen.insert(Reg);
     if (Reg.isPhysical()) {
       for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
-                SubRegs.isValid(); ++SubRegs) {
-            Info.Gen.insert(*SubRegs);
+           SubRegs.isValid(); ++SubRegs) {
+        Info.Gen.insert(*SubRegs);
       }
     }
   }
@@ -324,8 +326,7 @@ void RISCVLiveVariables::computeGlobalLiveness(MachineFunction &MF) {
   }
 }
 
-bool RISCVLiveVariables::isLiveAt(Register Reg,
-                                   const MachineInstr &MI) const {
+bool RISCVLiveVariables::isLiveAt(Register Reg, const MachineInstr &MI) const {
   const MachineBasicBlock *MBB = MI.getParent();
   auto It = BlockLiveness.find(MBB);
 
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 9611920957ab4..0a991c144d1cf 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -110,7 +110,7 @@ static cl::opt<bool> EnableCFIInstrInserter(
     cl::Hidden);
 
 static cl::opt<bool> EnableRISCVLiveVariables(
-    "riscv-live-variables",
+    "riscv-enable-live-variables",
     cl::desc("Enable Live Variable Analysis for RISC-V"), cl::init(false),
     cl::Hidden);
 
diff --git a/llvm/test/CodeGen/RISCV/machine-live-variables.mir b/llvm/test/CodeGen/RISCV/machine-live-variables.mir
index 734184964f50c..51033658f0cfb 100644
--- a/llvm/test/CodeGen/RISCV/machine-live-variables.mir
+++ b/llvm/test/CodeGen/RISCV/machine-live-variables.mir
@@ -1,18 +1,13 @@
-# RUN: llc -mtriple=riscv64 -verify-machineinstrs -run-pass=riscv-live-variables -debug < %s | FileCheck %s
+# RUN: llc -x mir -mtriple=riscv64 -verify-machineinstrs -run-pass=riscv-live-variables -debug < %s 2>&1 \
+# RUN: | FileCheck %s
 
 # REQUIRES: asserts
 
-;CHECK: Block:  (Number: 1)
-;CHECK:   Live-In:  { }
-;CHECK:   Live-Out: { }
-;CHECK:   Use:      { }
-;CHECK:   Def:      { $x10 $x11 $x12 $x13 $x14 $x15 $x16 $x10_h $x11_h $x12_h $x13_h $x14_h $x15_h $x16_h $x10_w $x11_w $x12_w $x13_w $x14_w $x15_w $x16_w }
-;CHECK: 
-;CHECK: Block:  (Number: 0)
-;CHECK:   Live-In:  { $x11 $x12 $x13 $x14 $x15 $x16 $x17 $x11_h $x12_h $x13_h $x14_h $x15_h $x16_h $x17_h $x11_w $x12_w $x13_w $x14_w $x15_w $x16_w $x17_w }
-;CHECK:   Live-Out: { }
-;CHECK:   Use:      { $x11 $x12 $x13 $x14 $x15 $x16 $x17 $x11_h $x12_h $x13_h $x14_h $x15_h $x16_h $x17_h $x11_w $x12_w $x13_w $x14_w $x15_w $x16_w $x17_w }
-;CHECK:   Def:      { $x10 $x11 $x12 $x10_h $x11_h $x12_h $x10_w $x11_w $x12_w }
+# CHECK: Block: (Number: 0)
+# CHECK:   Live-In:  { $x11 $x12 $x13 $x14 $x15 $x16 $x17 $x11_h $x12_h $x13_h $x14_h $x15_h $x16_h $x17_h $x11_w $x12_w $x13_w $x14_w $x15_w $x16_w $x17_w }
+# CHECK:   Live-Out: { }
+# CHECK:   Use:      { $x11 $x12 $x13 $x14 $x15 $x16 $x17 $x11_h $x12_h $x13_h $x14_h $x15_h $x16_h $x17_h $x11_w $x12_w $x13_w $x14_w $x15_w $x16_w $x17_w }
+# CHECK:   Def:      { $x10 $x11 $x12 $x10_h $x11_h $x12_h $x10_w $x11_w $x12_w }
 
 --- |
 
@@ -77,3 +72,5 @@ body: |
     SW killed renamable $x12, %stack.0.va, 4 :: (store (s32) into %ir.va + 4)
     renamable $x10 = LW killed renamable $x10, 0 :: (load (s32) from %ir.argp.cur)
     PseudoRET implicit $x10
+
+...

>From 303ef1297313bc6d830c72db5d48141c4fe8cf55 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sat, 15 Nov 2025 23:36:23 -0800
Subject: [PATCH 07/32] Update kill of individual instructions

---
 llvm/lib/Target/RISCV/RISCV.h                |  2 +-
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp | 94 ++++++++++++++++++--
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp |  4 +-
 3 files changed, 90 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h
index 9fb6a603e481d..558d7d1987570 100644
--- a/llvm/lib/Target/RISCV/RISCV.h
+++ b/llvm/lib/Target/RISCV/RISCV.h
@@ -108,7 +108,7 @@ void initializeRISCVPreAllocZilsdOptPass(PassRegistry &);
 FunctionPass *createRISCVZacasABIFixPass();
 void initializeRISCVZacasABIFixPass(PassRegistry &);
 
-FunctionPass *createRISCVLiveVariablesPass();
+FunctionPass *createRISCVLiveVariablesPass(bool PreRegAlloc);
 void initializeRISCVLiveVariablesPass(PassRegistry &);
 
 InstructionSelector *
diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index 5a9f192ad23ce..193070613a436 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -21,6 +21,7 @@
 #include "RISCV.h"
 #include "RISCVInstrInfo.h"
 #include "RISCVSubtarget.h"
+#include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/PostOrderIterator.h"
 #include "llvm/ADT/Statistic.h"
@@ -33,6 +34,8 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
+
+#include <unordered_map>
 #include <set>
 
 using namespace llvm;
@@ -43,6 +46,10 @@ using namespace llvm;
 STATISTIC(NumLiveRegsAtEntry, "Number of registers live at function entry");
 STATISTIC(NumLiveRegsTotal, "Total number of live registers across all blocks");
 
+static cl::opt<bool> UpdateKills("riscv-liveness-update-kills",
+                                 cl::desc("Update kill flags"), cl::init(false),
+                                 cl::Hidden);
+
 namespace {
 
 /// LivenessInfo - Stores liveness information for a basic block
@@ -67,14 +74,14 @@ class RISCVLiveVariables : public MachineFunctionPass {
 public:
   static char ID;
 
-  RISCVLiveVariables() : MachineFunctionPass(ID) {
+  RISCVLiveVariables(bool PreRegAlloc)
+      : MachineFunctionPass(ID), PreRegAlloc(PreRegAlloc) {
     initializeRISCVLiveVariablesPass(*PassRegistry::getPassRegistry());
   }
 
   bool runOnMachineFunction(MachineFunction &MF) override;
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.setPreservesAll();
     MachineFunctionPass::getAnalysisUsage(AU);
   }
 
@@ -102,6 +109,9 @@ class RISCVLiveVariables : public MachineFunctionPass {
 
   void verifyLiveness(MachineFunction &MF) const;
 
+  /// Mark operands that kill a register
+  void markKills(MachineFunction &MF);
+
 private:
   /// Compute local liveness information (Use and Def sets) for each block
   void computeLocalLiveness(MachineFunction &MF);
@@ -117,6 +127,13 @@ class RISCVLiveVariables : public MachineFunctionPass {
   bool isTrackableRegister(Register Reg, const TargetRegisterInfo *TRI,
                            const MachineRegisterInfo *MRI) const;
 
+  bool PreRegAlloc;
+  unsigned RegCounter = 0;
+
+  // PreRA can have large number of registers and basic block
+  // level liveness may be expensive without a bitvector representation.
+  std::unordered_map<unsigned, unsigned> TrackedRegisters;
+
   /// Liveness information for each basic block
   DenseMap<const MachineBasicBlock *, LivenessInfo> BlockLiveness;
 
@@ -134,8 +151,8 @@ char RISCVLiveVariables::ID = 0;
 INITIALIZE_PASS(RISCVLiveVariables, DEBUG_TYPE, RISCV_LIVE_VARIABLES_NAME,
                 false, true)
 
-FunctionPass *llvm::createRISCVLiveVariablesPass() {
-  return new RISCVLiveVariables();
+FunctionPass *llvm::createRISCVLiveVariablesPass(bool PreRegAlloc) {
+  return new RISCVLiveVariables(PreRegAlloc);
 }
 
 bool RISCVLiveVariables::isTrackableRegister(
@@ -170,6 +187,8 @@ void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
 
     Register Reg = MO.getReg();
 
+    TrackedRegisters.insert(std::pair(Reg, RegCounter++));
+
     // Skip non-trackable registers
     if (!isTrackableRegister(Reg, TRI, MRI))
       continue;
@@ -277,10 +296,7 @@ void RISCVLiveVariables::computeGlobalLiveness(MachineFunction &MF) {
     Changed = false;
     ++Iterations;
 
-    // Process blocks in **post-order** for better convergence
-    ReversePostOrderTraversal<MachineFunction *> RPOT(&MF);
-
-    for (MachineBasicBlock *MBB : RPOT) {
+    for (MachineBasicBlock *MBB : post_order(&MF)) {
       LivenessInfo &Info = BlockLiveness[MBB];
       std::set<Register> OldLiveIn = Info.LiveIn;
       std::set<Register> NewLiveOut;
@@ -368,6 +384,62 @@ void RISCVLiveVariables::verifyLiveness(MachineFunction &MF) const {
   }
 }
 
+void RISCVLiveVariables::markKills(MachineFunction &MF) {
+    auto KillSetSize = PreRegAlloc ? RegCounter : TRI->getNumRegs();
+    for (MachineBasicBlock *MBB : post_order(&MF)) {
+    // Set all the registers that are not live-out of the block.
+    // Since the global liveness is available (even though a bit conservative),
+    // this initialization is safe.
+    llvm::BitVector KillSet(KillSetSize, true);
+    LivenessInfo &Info = BlockLiveness[MBB];
+
+    for (Register Reg : Info.LiveOut) {
+      auto RegIdx = PreRegAlloc ? TrackedRegisters[Reg] : Reg.asMCReg().id();
+      KillSet.reset(RegIdx);
+    }
+
+    for (MachineInstr &MI : reverse(*MBB)) {
+      for (MachineOperand &MO : MI.operands()) {
+        if (!MO.isReg())
+          continue;
+
+        Register Reg = MO.getReg();
+        // Does not track physical registers pre-regalloc.
+        if ((PreRegAlloc && Reg.isPhysical()) || !isTrackableRegister(Reg, TRI, MRI))
+          continue;
+
+        assert(TrackedRegisters.find(Reg) != TrackedRegisters.end() &&
+               "Register not tracked");
+        auto RegIdx = PreRegAlloc ? TrackedRegisters[Reg] : Reg.asMCReg().id();
+
+        if (MO.isDef()) {
+          KillSet.set(RegIdx);
+
+          // Also handle sub-registers for physical registers
+          if (!PreRegAlloc && Reg.isPhysical()) {
+            for (MCRegAliasIterator RA(Reg, TRI, true); RA.isValid(); ++RA)
+              KillSet.set(*RA);
+          }
+          continue;
+        }
+
+        // Use.
+        if (KillSet[RegIdx]) {
+          if (!MO.isKill() && !MI.isPHI() && !MI.isCall())
+            MO.setIsKill(true);
+          LLVM_DEBUG(dbgs() << "Marking kill of " << printReg(Reg, TRI)
+                            << " at instruction: " << MI);
+          KillSet.reset(RegIdx);
+          if (Reg.isPhysical()) {
+            for (MCRegAliasIterator RA(Reg, TRI, true); RA.isValid(); ++RA)
+              KillSet.reset(*RA);
+          }
+        }
+      }
+    }
+  }
+}
+
 bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
   if (skipFunction(MF.getFunction()) || MF.empty())
     return false;
@@ -396,6 +468,12 @@ bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
   // Step 2: Compute global liveness (LiveIn and LiveOut sets)
   computeGlobalLiveness(MF);
 
+  // TODO: Update live-in/live-out sets of MBBs
+
+  // Step 3: Mark kill flags on operands
+  if (UpdateKills)
+    markKills(MF);
+
   LLVM_DEBUG({
     dbgs() << "\n***** Final Liveness Information *****\n";
     print(dbgs());
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 0a991c144d1cf..4db4d3010d730 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -622,6 +622,8 @@ void RISCVPassConfig::addMachineSSAOptimization() {
 
   addPass(createRISCVVectorPeepholePass());
   addPass(createRISCVFoldMemOffsetPass());
+  if (EnableRISCVLiveVariables)
+    addPass(createRISCVLiveVariablesPass(true));
 
   TargetPassConfig::addMachineSSAOptimization();
 
@@ -660,7 +662,7 @@ void RISCVPassConfig::addPostRegAlloc() {
     addPass(createRISCVRedundantCopyEliminationPass());
 
   if (EnableRISCVLiveVariables)
-    addPass(createRISCVLiveVariablesPass());
+    addPass(createRISCVLiveVariablesPass(false));
 }
 
 bool RISCVPassConfig::addILPOpts() {

>From ecacb069f2f209c8424d4e2435e1efc4a2af6581 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sat, 15 Nov 2025 23:40:55 -0800
Subject: [PATCH 08/32] Add test from  #166141

---
 .../RISCV/live-variables-pre-regalloc.ll      | 65 +++++++++++++++++++
 1 file changed, 65 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/live-variables-pre-regalloc.ll

diff --git a/llvm/test/CodeGen/RISCV/live-variables-pre-regalloc.ll b/llvm/test/CodeGen/RISCV/live-variables-pre-regalloc.ll
new file mode 100644
index 0000000000000..c3465b07dd65c
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/live-variables-pre-regalloc.ll
@@ -0,0 +1,65 @@
+; RUN: llc -mtriple riscv64 -mattr=+d -riscv-enable-live-variables --stop-after=riscv-live-variables -riscv-liveness-update-kills < %s | FileCheck %s
+
+; Issue: #166141 Pessimistic MachineLICM due to missing liveness info.
+
+; CHECK: %42:fpr64 = nofpexcept FMUL_D killed %2, killed %41, 7, implicit $frm
+
+define void @f(ptr %p) {
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i64 [0, %entry], [%iv.next, %latch]
+
+  %gep = getelementptr double, ptr %p, i64 %iv
+
+  %x = load double, ptr %gep
+  %y0 = fmul double %x, %x
+  %y1 = fmul double %y0, %y0
+  %y2 = fmul double %y1, %y1
+  %y3 = fmul double %y2, %y2
+  %y4 = fmul double %y3, %y3
+  %y5 = fmul double %y4, %y4
+  %y6 = fmul double %y5, %y5
+  %y7 = fmul double %y6, %y6
+  %y8 = fmul double %y7, %y7
+  %y9 = fmul double %y8, %y8
+  %y10 = fmul double %y9, %y9
+  %y11 = fmul double %y10, %y10
+  %y12 = fmul double %y11, %y11
+  %y13 = fmul double %y12, %y12
+  %y14 = fmul double %y13, %y13
+  %y15 = fmul double %y14, %y14
+  %y16 = fmul double %y15, %y15
+  %y17 = fmul double %y16, %y16
+  %y18 = fmul double %y17, %y17
+  %y19 = fmul double %y18, %y18
+  %y20 = fmul double %y19, %y19
+  %y21 = fmul double %y20, %y20
+  %y22 = fmul double %y21, %y21
+  %y23 = fmul double %y22, %y22
+  %y24 = fmul double %y23, %y23
+  %y25 = fmul double %y24, %y24
+  %y26 = fmul double %y25, %y25
+  %y27 = fmul double %y26, %y26
+  %y28 = fmul double %y27, %y27
+  %y29 = fmul double %y28, %y28
+  %y30 = fmul double %y29, %y29
+  %y31 = fmul double %y30, %y30
+
+  %c = fcmp une double %y31, 0.0
+  br i1 %c, label %if, label %latch
+
+if:
+  %z = fmul double %y31, 3.14159274101257324218750
+  store double %z, ptr %gep
+  br label %latch
+
+latch:
+  %iv.next = add i64 %iv, 1
+  %ec = icmp eq i64 %iv.next, 1024
+  br i1 %ec, label %exit, label %loop
+
+exit:
+  ret void
+}

>From 82a8b6f991ea31e428985437749f5871c96c3f1d Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sun, 16 Nov 2025 00:43:40 -0800
Subject: [PATCH 09/32] clang-format and add correct flags to the tests

---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp          | 9 +++++----
 llvm/test/CodeGen/RISCV/live-variables-basic.mir      | 2 +-
 llvm/test/CodeGen/RISCV/live-variables-calls.mir      | 2 +-
 llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir | 2 +-
 llvm/test/CodeGen/RISCV/live-variables-loops.mir      | 2 +-
 llvm/test/CodeGen/RISCV/live-variables-rv64.mir       | 5 ++---
 llvm/test/CodeGen/RISCV/machine-live-variables.mir    | 2 +-
 7 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index 193070613a436..2e63bc8aeb207 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -35,8 +35,8 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 
-#include <unordered_map>
 #include <set>
+#include <unordered_map>
 
 using namespace llvm;
 
@@ -385,8 +385,8 @@ void RISCVLiveVariables::verifyLiveness(MachineFunction &MF) const {
 }
 
 void RISCVLiveVariables::markKills(MachineFunction &MF) {
-    auto KillSetSize = PreRegAlloc ? RegCounter : TRI->getNumRegs();
-    for (MachineBasicBlock *MBB : post_order(&MF)) {
+  auto KillSetSize = PreRegAlloc ? RegCounter : TRI->getNumRegs();
+  for (MachineBasicBlock *MBB : post_order(&MF)) {
     // Set all the registers that are not live-out of the block.
     // Since the global liveness is available (even though a bit conservative),
     // this initialization is safe.
@@ -405,7 +405,8 @@ void RISCVLiveVariables::markKills(MachineFunction &MF) {
 
         Register Reg = MO.getReg();
         // Does not track physical registers pre-regalloc.
-        if ((PreRegAlloc && Reg.isPhysical()) || !isTrackableRegister(Reg, TRI, MRI))
+        if ((PreRegAlloc && Reg.isPhysical()) ||
+            !isTrackableRegister(Reg, TRI, MRI))
           continue;
 
         assert(TrackedRegisters.find(Reg) != TrackedRegisters.end() &&
diff --git a/llvm/test/CodeGen/RISCV/live-variables-basic.mir b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
index 3339b04602953..bc3cee44b3878 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-basic.mir
+++ b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
@@ -1,5 +1,5 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=riscv64 -run-pass=riscv-live-variables -verify-machineinstrs -o - %s | FileCheck %s
+# RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs -o - %s | FileCheck %s
 #
 # Test basic live variable analysis with simple control flow and basic blocks
 
diff --git a/llvm/test/CodeGen/RISCV/live-variables-calls.mir b/llvm/test/CodeGen/RISCV/live-variables-calls.mir
index 2a2738eaa3bad..16095ad5a1715 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-calls.mir
+++ b/llvm/test/CodeGen/RISCV/live-variables-calls.mir
@@ -1,5 +1,5 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=riscv64 -run-pass=riscv-live-variables -verify-machineinstrs -o - %s | FileCheck %s
+# RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs -o - %s | FileCheck %s
 #
 # Test live variable analysis with function calls and register clobbering
 # Function calls clobber caller-saved registers, which affects liveness
diff --git a/llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir b/llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir
index 4e04de8a310a4..fe53094ddac8d 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir
+++ b/llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir
@@ -1,5 +1,5 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=riscv64 -run-pass=riscv-live-variables -verify-machineinstrs -o - %s | FileCheck %s
+# RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs -o - %s | FileCheck %s
 #
 # Test live variable analysis edge cases and special scenarios
 # Including: dead code, unreachable blocks, critical edges, and complex phi nodes
diff --git a/llvm/test/CodeGen/RISCV/live-variables-loops.mir b/llvm/test/CodeGen/RISCV/live-variables-loops.mir
index 05e24b33a1131..1588c65ed0ebf 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-loops.mir
+++ b/llvm/test/CodeGen/RISCV/live-variables-loops.mir
@@ -1,5 +1,5 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=riscv64 -run-pass=riscv-live-variables -verify-machineinstrs -o - %s | FileCheck %s
+# RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs -o - %s | FileCheck %s
 #
 # Test live variable analysis with loops and backward edges
 # Loops create interesting liveness patterns with phi nodes and variables
diff --git a/llvm/test/CodeGen/RISCV/live-variables-rv64.mir b/llvm/test/CodeGen/RISCV/live-variables-rv64.mir
index 5b396373a60f4..c3b8ec003a5b6 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-rv64.mir
+++ b/llvm/test/CodeGen/RISCV/live-variables-rv64.mir
@@ -1,5 +1,5 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=riscv64 -run-pass=riscv-live-variables -verify-machineinstrs -o - %s | FileCheck %s
+# RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs -o - %s | FileCheck %s
 #
 # Test live variable analysis for RV64-specific scenarios
 # This includes 64-bit operations, wide registers, and RV64-specific instructions
@@ -70,10 +70,9 @@ body:             |
 
     %0:gpr = COPY $x10
     %1:gpr = COPY $x11
-    ; SLLI for 64-bit shift (RV64-specific immediate range)
     %2:gpr = SLLI %0, 32
     %3:gpr = OR %2, %1
-    $x10 = COPY %3
+    %4:gpr = COPY %3
     PseudoRET implicit $x10
 ...
 ---
diff --git a/llvm/test/CodeGen/RISCV/machine-live-variables.mir b/llvm/test/CodeGen/RISCV/machine-live-variables.mir
index 51033658f0cfb..964324323bf06 100644
--- a/llvm/test/CodeGen/RISCV/machine-live-variables.mir
+++ b/llvm/test/CodeGen/RISCV/machine-live-variables.mir
@@ -1,4 +1,4 @@
-# RUN: llc -x mir -mtriple=riscv64 -verify-machineinstrs -run-pass=riscv-live-variables -debug < %s 2>&1 \
+# RUN: llc -x mir -mtriple=riscv64 -verify-machineinstrs -riscv-enable-live-variables -debug < %s 2>&1 \
 # RUN: | FileCheck %s
 
 # REQUIRES: asserts

>From e9a81494f73777661a2f2c4403174c0f2c295384 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sun, 16 Nov 2025 12:14:02 -0800
Subject: [PATCH 10/32] Use uses and defs iterator to make sure defs are
 processed before uses

---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp | 33 +++++++++++---------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index 2e63bc8aeb207..79397836d1bae 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -399,10 +399,7 @@ void RISCVLiveVariables::markKills(MachineFunction &MF) {
     }
 
     for (MachineInstr &MI : reverse(*MBB)) {
-      for (MachineOperand &MO : MI.operands()) {
-        if (!MO.isReg())
-          continue;
-
+      for (MachineOperand &MO : MI.all_defs()) {
         Register Reg = MO.getReg();
         // Does not track physical registers pre-regalloc.
         if ((PreRegAlloc && Reg.isPhysical()) ||
@@ -413,20 +410,28 @@ void RISCVLiveVariables::markKills(MachineFunction &MF) {
                "Register not tracked");
         auto RegIdx = PreRegAlloc ? TrackedRegisters[Reg] : Reg.asMCReg().id();
 
-        if (MO.isDef()) {
-          KillSet.set(RegIdx);
+        KillSet.set(RegIdx);
 
-          // Also handle sub-registers for physical registers
-          if (!PreRegAlloc && Reg.isPhysical()) {
-            for (MCRegAliasIterator RA(Reg, TRI, true); RA.isValid(); ++RA)
-              KillSet.set(*RA);
-          }
-          continue;
+        // Also handle sub-registers for physical registers
+        if (!PreRegAlloc && Reg.isPhysical()) {
+          for (MCRegAliasIterator RA(Reg, TRI, true); RA.isValid(); ++RA)
+            KillSet.set(*RA);
         }
+      }
+
+      for (MachineOperand &MO : MI.all_uses()) {
+        Register Reg = MO.getReg();
+        // Does not track physical registers pre-regalloc.
+        if ((PreRegAlloc && Reg.isPhysical()) ||
+            !isTrackableRegister(Reg, TRI, MRI))
+          continue;
+
+        assert(TrackedRegisters.find(Reg) != TrackedRegisters.end() &&
+               "Register not tracked");
+        auto RegIdx = PreRegAlloc ? TrackedRegisters[Reg] : Reg.asMCReg().id();
 
-        // Use.
         if (KillSet[RegIdx]) {
-          if (!MO.isKill() && !MI.isPHI() && !MI.isCall())
+          if (!MO.isKill() && !MI.isPHI())
             MO.setIsKill(true);
           LLVM_DEBUG(dbgs() << "Marking kill of " << printReg(Reg, TRI)
                             << " at instruction: " << MI);

>From 4c2dcb2c7250010a592074b495fad1f47462f7a1 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sun, 16 Nov 2025 12:14:29 -0800
Subject: [PATCH 11/32] Update test cases to stop after live variables

---
 .../RISCV/live-variables-edge-cases.ll        | 206 +++++++++++++
 .../RISCV/live-variables-edge-cases.mir       | 285 ------------------
 .../CodeGen/RISCV/live-variables-loops.ll     | 162 ++++++++++
 .../CodeGen/RISCV/live-variables-loops.mir    | 238 ---------------
 .../test/CodeGen/RISCV/live-variables-rv64.ll | 127 ++++++++
 .../CodeGen/RISCV/live-variables-rv64.mir     | 187 ------------
 6 files changed, 495 insertions(+), 710 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/live-variables-edge-cases.ll
 delete mode 100644 llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir
 create mode 100644 llvm/test/CodeGen/RISCV/live-variables-loops.ll
 delete mode 100644 llvm/test/CodeGen/RISCV/live-variables-loops.mir
 create mode 100644 llvm/test/CodeGen/RISCV/live-variables-rv64.ll
 delete mode 100644 llvm/test/CodeGen/RISCV/live-variables-rv64.mir

diff --git a/llvm/test/CodeGen/RISCV/live-variables-edge-cases.ll b/llvm/test/CodeGen/RISCV/live-variables-edge-cases.ll
new file mode 100644
index 0000000000000..6cac878940969
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/live-variables-edge-cases.ll
@@ -0,0 +1,206 @@
+; RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs \
+; RUN: -riscv-enable-live-variables -riscv-liveness-update-kills -stop-after=riscv-live-variables \
+; RUN: -o - %s | FileCheck %s
+
+; Test live variable analysis edge cases and special scenarios
+; Including: dead code, unreachable blocks, critical edges, and complex phi nodes
+
+; CHECK: test_dead_code
+; CHECK:   bb.0.entry:
+; CHECK:     liveins: $x10
+; CHECK:     %0:gpr = COPY $x10
+; CHECK:     $x10 = COPY killed %0
+; CHECK:     PseudoRET implicit $x10
+
+define i64 @test_dead_code(i64 %a, i64 %b) {
+entry:
+  %dead = add i64 %a, %b
+  ret i64 %a
+}
+
+; CHECK: test_critical_edge
+; CHECK:  bb.0.entry:
+; CHECK:    successors: %bb.2(0x50000000), %bb.1(0x30000000)
+; CHECK:    liveins: $x10, $x11, $x12
+;
+; CHECK:    %5:gpr = COPY $x12
+; CHECK:    %4:gpr = COPY $x11
+; CHECK:    %3:gpr = COPY $x10
+; CHECK:    %6:gpr = COPY $x0
+; CHECK:    BLT killed %6, %3, %bb.2
+; CHECK:    PseudoBR %bb.1
+;
+; CHECK:  bb.1.check2:
+; CHECK:    successors: %bb.2(0x50000000), %bb.3(0x30000000)
+;
+; CHECK:    %7:gpr = COPY $x0
+; CHECK:    BGE killed %7, %4, %bb.3
+; CHECK:    PseudoBR %bb.2
+;
+; CHECK:  bb.2.then:
+; CHECK:    successors: %bb.4(0x80000000)
+;
+; CHECK:    ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:    $x10 = COPY killed %3
+; CHECK:    $x11 = COPY killed %4
+; CHECK:    PseudoCALL target-flags(riscv-call) &__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+; CHECK:    ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:    %8:gpr = COPY $x10
+; CHECK:    %0:gpr = COPY killed %8
+; CHECK:    PseudoBR %bb.4
+;
+; CHECK:  bb.3.else:
+; CHECK:    successors: %bb.4(0x80000000)
+;
+; CHECK:    %1:gpr = SUB killed %3, killed %5
+;
+; CHECK:  bb.4.end:
+; CHECK:    %2:gpr = PHI %1, %bb.3, %0, %bb.2
+; CHECK:    $x10 = COPY killed %2
+; CHECK:    PseudoRET implicit $x10
+
+define i64 @test_critical_edge(i64 %a, i64 %b, i64 %c) {
+entry:
+  %cmp1 = icmp sgt i64 %a, 0
+  br i1 %cmp1, label %then, label %check2
+
+check2:
+  %cmp2 = icmp sgt i64 %b, 0
+  br i1 %cmp2, label %then, label %else
+
+then:
+  %mul = mul i64 %a, %b
+  br label %end
+
+else:
+  %sub = sub i64 %a, %c
+  br label %end
+
+end:
+  %result = phi i64 [ %mul, %then ], [ %sub, %else ]
+  ret i64 %result
+}
+
+; CHECK: test_complex_phi
+; CHECK:   bb.0.entry:
+; CHECK:     successors: %bb.1(0x50000000), %bb.2(0x30000000)
+; CHECK:     liveins: $x10, $x11, $x12, $x13
+;
+; CHECK:     %7:gpr = COPY $x13
+; CHECK:     %6:gpr = COPY $x12
+; CHECK:     %5:gpr = COPY $x11
+; CHECK:     %4:gpr = COPY $x10
+; CHECK:     %8:gpr = COPY $x0
+; CHECK:     BGE killed %8, %4, %bb.2
+; CHECK:     PseudoBR %bb.1
+;
+; CHECK:   bb.1.path1:
+; CHECK:     successors: %bb.5(0x80000000)
+;
+; CHECK:     %0:gpr = ADD killed %4, killed %5
+; CHECK:     PseudoBR %bb.5
+;
+; CHECK:   bb.2.path2:
+; CHECK:     successors: %bb.3(0x50000000), %bb.4(0x30000000)
+;
+; CHECK:     %9:gpr = COPY $x0
+; CHECK:     BGE killed %9, %6, %bb.4
+; CHECK:     PseudoBR %bb.3
+;
+; CHECK:   bb.3.path2a:
+; CHECK:     successors: %bb.5(0x80000000)
+;
+; CHECK:     ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:     $x10 = COPY killed %6
+; CHECK:     $x11 = COPY killed %7
+; CHECK:     PseudoCALL target-flags(riscv-call) &__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+; CHECK:     ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:     %10:gpr = COPY $x10
+; CHECK:     %1:gpr = COPY killed %10
+; CHECK:     PseudoBR %bb.5
+;
+; CHECK:   bb.4.path2b:
+; CHECK:     successors: %bb.5(0x80000000)
+;
+; CHECK:     %2:gpr = SUB killed %6, killed %7
+;
+; CHECK:   bb.5.merge:
+; CHECK:     %3:gpr = PHI %2, %bb.4, %1, %bb.3, %0, %bb.1
+; CHECK:     $x10 = COPY killed %3
+; CHECK:     PseudoRET implicit $x10
+
+define i64 @test_complex_phi(i64 %a, i64 %b, i64 %c, i64 %d) {
+entry:
+  %cmp1 = icmp sgt i64 %a, 0
+  br i1 %cmp1, label %path1, label %path2
+
+path1:
+  %v1 = add i64 %a, %b
+  br label %merge
+
+path2:
+  %cmp2 = icmp sgt i64 %c, 0
+  br i1 %cmp2, label %path2a, label %path2b
+
+path2a:
+  %v2a = mul i64 %c, %d
+  br label %merge
+
+path2b:
+  %v2b = sub i64 %c, %d
+  br label %merge
+
+merge:
+  %result = phi i64 [ %v1, %path1 ], [ %v2a, %path2a ], [ %v2b, %path2b ]
+  ret i64 %result
+}
+
+; CHECK: test_use_after_def
+; CHECK:   bb.0.entry:
+; CHECK:     liveins: $x10
+;
+; CHECK:     %0:gpr = COPY $x10
+; CHECK:     %1:gpr = ADDI killed %0, 1
+; CHECK:     %2:gpr = ADD killed %1, %1
+; CHECK:     %3:gpr = ADDI killed %2, 5
+; CHECK:     $x10 = COPY killed %3
+; CHECK:     PseudoRET implicit $x10
+
+define i64 @test_use_after_def(i64 %a) {
+entry:
+  %v1 = add i64 %a, 1
+  %v2 = add i64 %v1, 2
+  %v3 = add i64 %v2, 3
+  %v4 = add i64 %v1, %v3
+  ret i64 %v4
+}
+
+; CHECK: test_implicit_defs
+; CHECK:   bb.0.entry:
+; CHECK:     liveins: $x10, $x11
+;
+; CHECK:     %1:gpr = COPY $x11
+; CHECK:     %0:gpr = COPY $x10
+; CHECK:     ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:     $x10 = COPY %0
+; CHECK:     $x11 = COPY %1
+; CHECK:     PseudoCALL target-flags(riscv-call) &__divdi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+; CHECK:     ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:     %2:gpr = COPY $x10
+; CHECK:     ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:     $x10 = COPY killed %0
+; CHECK:     $x11 = COPY killed %1
+; CHECK:     PseudoCALL target-flags(riscv-call) &__moddi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+; CHECK:     ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:     %3:gpr = COPY $x10
+; CHECK:     %4:gpr = ADD killed %2, killed %3
+; CHECK:     $x10 = COPY killed %4
+; CHECK:     PseudoRET implicit $x10
+
+define i64 @test_implicit_defs(i64 %a, i64 %b) {
+entry:
+  %div = sdiv i64 %a, %b
+  %rem = srem i64 %a, %b
+  %sum = add i64 %div, %rem
+  ret i64 %sum
+}
diff --git a/llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir b/llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir
deleted file mode 100644
index fe53094ddac8d..0000000000000
--- a/llvm/test/CodeGen/RISCV/live-variables-edge-cases.mir
+++ /dev/null
@@ -1,285 +0,0 @@
-# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs -o - %s | FileCheck %s
-#
-# Test live variable analysis edge cases and special scenarios
-# Including: dead code, unreachable blocks, critical edges, and complex phi nodes
-
---- |
-  define i64 @test_dead_code(i64 %a, i64 %b) {
-  entry:
-    %dead = add i64 %a, %b
-    ret i64 %a
-  }
-
-  define i64 @test_critical_edge(i64 %a, i64 %b, i64 %c) {
-  entry:
-    %cmp1 = icmp sgt i64 %a, 0
-    br i1 %cmp1, label %then, label %check2
-
-  check2:
-    %cmp2 = icmp sgt i64 %b, 0
-    br i1 %cmp2, label %then, label %else
-
-  then:
-    %mul = mul i64 %a, %b
-    br label %end
-
-  else:
-    %sub = sub i64 %a, %c
-    br label %end
-
-  end:
-    %result = phi i64 [ %mul, %then ], [ %sub, %else ]
-    ret i64 %result
-  }
-
-  define i64 @test_complex_phi(i64 %a, i64 %b, i64 %c, i64 %d) {
-  entry:
-    %cmp1 = icmp sgt i64 %a, 0
-    br i1 %cmp1, label %path1, label %path2
-
-  path1:
-    %v1 = add i64 %a, %b
-    br label %merge
-
-  path2:
-    %cmp2 = icmp sgt i64 %c, 0
-    br i1 %cmp2, label %path2a, label %path2b
-
-  path2a:
-    %v2a = mul i64 %c, %d
-    br label %merge
-
-  path2b:
-    %v2b = sub i64 %c, %d
-    br label %merge
-
-  merge:
-    %result = phi i64 [ %v1, %path1 ], [ %v2a, %path2a ], [ %v2b, %path2b ]
-    ret i64 %result
-  }
-
-  define i64 @test_use_after_def(i64 %a) {
-  entry:
-    %v1 = add i64 %a, 1
-    %v2 = add i64 %v1, 2
-    %v3 = add i64 %v2, 3
-    %v4 = add i64 %v1, %v3
-    ret i64 %v4
-  }
-
-  define i64 @test_implicit_defs(i64 %a, i64 %b) {
-  entry:
-    %div = sdiv i64 %a, %b
-    %rem = srem i64 %a, %b
-    %sum = add i64 %div, %rem
-    ret i64 %sum
-  }
-...
----
-name:            test_dead_code
-alignment:       4
-tracksRegLiveness: true
-registers:
-  - { id: 0, class: gpr }
-  - { id: 1, class: gpr }
-  - { id: 2, class: gpr }
-liveins:
-  - { reg: '$x10', virtual-reg: '%0' }
-  - { reg: '$x11', virtual-reg: '%1' }
-body:             |
-  bb.0.entry:
-    liveins: $x10, $x11
-    ; CHECK-LABEL: name: test_dead_code
-    ; CHECK: bb.0.entry:
-    ; CHECK-NEXT: liveins: $x10, $x11
-    ; %2 is dead - never used, should not affect liveness of inputs
-
-    %0:gpr = COPY $x10
-    %1:gpr = COPY $x11
-    ; Dead instruction - result never used
-    %2:gpr = ADD %0, %1
-    ; Only %0 should be live here
-    $x10 = COPY %0
-    PseudoRET implicit $x10
-...
----
-name:            test_critical_edge
-alignment:       4
-tracksRegLiveness: true
-registers:
-  - { id: 0, class: gpr }
-  - { id: 1, class: gpr }
-  - { id: 2, class: gpr }
-  - { id: 3, class: gpr }
-  - { id: 4, class: gpr }
-  - { id: 5, class: gpr }
-  - { id: 6, class: gpr }
-  - { id: 7, class: gpr }
-liveins:
-  - { reg: '$x10', virtual-reg: '%0' }
-  - { reg: '$x11', virtual-reg: '%1' }
-  - { reg: '$x12', virtual-reg: '%2' }
-body:             |
-  bb.0.entry:
-    liveins: $x10, $x11, $x12
-    ; CHECK-LABEL: name: test_critical_edge
-    ; CHECK: bb.0.entry:
-
-    %0:gpr = COPY $x10
-    %1:gpr = COPY $x11
-    %2:gpr = COPY $x12
-    %3:gpr = SLTI %0, 1
-    BEQ %3, $x0, %bb.2
-
-  bb.1.check2:
-    ; CHECK: bb.1.check2:
-    ; %0, %1, %2 should all be live-in
-
-    %4:gpr = SLTI %1, 1
-    BEQ %4, $x0, %bb.3
-
-  bb.2.then:
-    ; CHECK: bb.2.then:
-    ; %0, %1 should be live-in (used in mul)
-
-    %5:gpr = MUL %0, %1
-    PseudoBR %bb.4
-
-  bb.3.else:
-    ; CHECK: bb.3.else:
-    ; %0, %2 should be live-in (used in sub)
-
-    %6:gpr = SUB %0, %2
-    PseudoBR %bb.4
-
-  bb.4.end:
-    ; CHECK: bb.4.end:
-    ; Either %5 or %6 should be live-in
-
-    %7:gpr = PHI %5, %bb.2, %6, %bb.3
-    $x10 = COPY %7
-    PseudoRET implicit $x10
-...
----
-name:            test_complex_phi
-alignment:       4
-tracksRegLiveness: true
-registers:
-  - { id: 0, class: gpr }
-  - { id: 1, class: gpr }
-  - { id: 2, class: gpr }
-  - { id: 3, class: gpr }
-  - { id: 4, class: gpr }
-  - { id: 5, class: gpr }
-  - { id: 6, class: gpr }
-  - { id: 7, class: gpr }
-  - { id: 8, class: gpr }
-  - { id: 9, class: gpr }
-liveins:
-  - { reg: '$x10', virtual-reg: '%0' }
-  - { reg: '$x11', virtual-reg: '%1' }
-  - { reg: '$x12', virtual-reg: '%2' }
-  - { reg: '$x13', virtual-reg: '%3' }
-body:             |
-  bb.0.entry:
-    liveins: $x10, $x11, $x12, $x13
-    ; CHECK-LABEL: name: test_complex_phi
-    ; CHECK: bb.0.entry:
-
-    %0:gpr = COPY $x10
-    %1:gpr = COPY $x11
-    %2:gpr = COPY $x12
-    %3:gpr = COPY $x13
-    %4:gpr = SLTI %0, 1
-    BEQ %4, $x0, %bb.2
-
-  bb.1.path1:
-    ; CHECK: bb.1.path1:
-
-    %5:gpr = ADD %0, %1
-    PseudoBR %bb.5
-
-  bb.2.path2:
-    ; CHECK: bb.2.path2:
-    ; %2, %3 should be live-in
-
-    %6:gpr = SLTI %2, 1
-    BEQ %6, $x0, %bb.4
-
-  bb.3.path2a:
-    ; CHECK: bb.3.path2a:
-
-    %7:gpr = MUL %2, %3
-    PseudoBR %bb.5
-
-  bb.4.path2b:
-    ; CHECK: bb.4.path2b:
-
-    %8:gpr = SUB %2, %3
-    PseudoBR %bb.5
-
-  bb.5.merge:
-    ; CHECK: bb.5.merge:
-    ; One of %5, %7, %8 should be live-in
-
-    %9:gpr = PHI %5, %bb.1, %7, %bb.3, %8, %bb.4
-    $x10 = COPY %9
-    PseudoRET implicit $x10
-...
----
-name:            test_use_after_def
-alignment:       4
-tracksRegLiveness: true
-registers:
-  - { id: 0, class: gpr }
-  - { id: 1, class: gpr }
-  - { id: 2, class: gpr }
-  - { id: 3, class: gpr }
-  - { id: 4, class: gpr }
-liveins:
-  - { reg: '$x10', virtual-reg: '%0' }
-body:             |
-  bb.0.entry:
-    liveins: $x10
-    ; CHECK-LABEL: name: test_use_after_def
-    ; CHECK: bb.0.entry:
-    ; Test that %1 remains live even after being used in %2
-
-    %0:gpr = COPY $x10
-    %1:gpr = ADDI %0, 1
-    %2:gpr = ADDI %1, 2
-    %3:gpr = ADDI %2, 3
-    ; %1 used again here - should have been kept live
-    %4:gpr = ADD %1, %3
-    $x10 = COPY %4
-    PseudoRET implicit $x10
-...
----
-name:            test_implicit_defs
-alignment:       4
-tracksRegLiveness: true
-registers:
-  - { id: 0, class: gpr }
-  - { id: 1, class: gpr }
-  - { id: 2, class: gpr }
-  - { id: 3, class: gpr }
-  - { id: 4, class: gpr }
-liveins:
-  - { reg: '$x10', virtual-reg: '%0' }
-  - { reg: '$x11', virtual-reg: '%1' }
-body:             |
-  bb.0.entry:
-    liveins: $x10, $x11
-    ; CHECK-LABEL: name: test_implicit_defs
-    ; CHECK: bb.0.entry:
-    ; Test handling of division which may have implicit defs/uses
-
-    %0:gpr = COPY $x10
-    %1:gpr = COPY $x11
-    %2:gpr = DIV %0, %1
-    %3:gpr = REM %0, %1
-    %4:gpr = ADD %2, %3
-    $x10 = COPY %4
-    PseudoRET implicit $x10
-...
diff --git a/llvm/test/CodeGen/RISCV/live-variables-loops.ll b/llvm/test/CodeGen/RISCV/live-variables-loops.ll
new file mode 100644
index 0000000000000..a689846baccbd
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/live-variables-loops.ll
@@ -0,0 +1,162 @@
+; RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs \
+; RUN: -riscv-enable-live-variables -riscv-liveness-update-kills -stop-after=riscv-live-variables \
+; RUN: -o - %s | FileCheck %s
+
+; Test live variable analysis with loops and backward edges
+; Loops create interesting liveness patterns with phi nodes and variables
+; that are live across backedges
+
+; CHECK:  test_simple_loop
+; CHECK:  bb.0.entry:
+; CHECK:    successors: %bb.1(0x80000000)
+; CHECK:    liveins: $x10
+;
+; CHECK:    %4:gpr = COPY $x10
+; CHECK:    %6:gpr = COPY $x0
+; CHECK:    %5:gpr = COPY killed %6
+;
+; CHECK:  bb.1.loop:
+; CHECK:    successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+;
+; CHECK:    %0:gpr = PHI %5, %bb.0, %3, %bb.1
+; CHECK:    %1:gpr = PHI %5, %bb.0, %2, %bb.1
+; CHECK:    %2:gpr = ADD killed %1, %0
+; CHECK:    %3:gpr = ADDI killed %0, 1
+; CHECK:    BLT %3, %4, %bb.1
+; CHECK:    PseudoBR %bb.2
+; 
+; CHECK:  bb.2.exit:
+; CHECK:    $x10 = COPY killed %2
+; CHECK:    PseudoRET implicit $x10
+
+define i64 @test_simple_loop(i64 %n) {
+entry:
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %sum = phi i64 [ 0, %entry ], [ %sum.next, %loop ]
+  %sum.next = add i64 %sum, %i
+  %i.next = add i64 %i, 1
+  %cmp = icmp slt i64 %i.next, %n
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret i64 %sum.next
+}
+
+; CHECK:  test_nested_loop
+; CHECK:  bb.0.entry:
+; CHECK:    successors: %bb.1(0x80000000)
+; CHECK:    liveins: $x10, $x11
+;
+; CHECK:    %11:gpr = COPY $x11
+; CHECK:    %10:gpr = COPY $x10
+; CHECK:    %13:gpr = COPY $x0
+; CHECK:    %12:gpr = COPY killed %13
+;
+; CHECK:  bb.1.outer.loop:
+; CHECK:    successors: %bb.2(0x80000000)
+;
+; CHECK:    %0:gpr = PHI %12, %bb.0, %9, %bb.3
+; CHECK:    %1:gpr = PHI %12, %bb.0, %8, %bb.3
+; CHECK:    %15:gpr = COPY $x0
+; CHECK:    %14:gpr = COPY killed %15
+;
+; CHECK:  bb.2.inner.loop:
+; CHECK:    successors: %bb.2(0x7c000000), %bb.3(0x04000000)
+;
+; CHECK:    %2:gpr = PHI %14, %bb.1, %7, %bb.2
+; CHECK:    %3:gpr = PHI %14, %bb.1, %6, %bb.2
+; CHECK:    %4:gpr = PHI %14, %bb.1, %5, %bb.2
+; CHECK:    %5:gpr = ADD %4, %2
+; CHECK:    %6:gpr = ADDI killed %3, 1
+; CHECK:    %7:gpr = ADD killed %2, %0
+; CHECK:    BLT %6, %11, %bb.2
+; CHECK:    PseudoBR %bb.3
+;
+; CHECK:  bb.3.outer.latch:
+; CHECK:    successors: %bb.1(0x7c000000), %bb.4(0x04000000)
+;
+; CHECK:    %8:gpr = ADD killed %1, %5
+; CHECK:    %9:gpr = ADDI killed %0, 1
+; CHECK:    BLT %9, %10, %bb.1
+; CHECK:    PseudoBR %bb.4
+;
+; CHECK:  bb.4.exit:
+; CHECK:    $x10 = COPY killed %8
+; CHECK:    PseudoRET implicit $x10
+
+define i64 @test_nested_loop(i64 %n, i64 %m) {
+entry:
+  br label %outer.loop
+
+outer.loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
+  %outer.sum = phi i64 [ 0, %entry ], [ %new.outer.sum, %outer.latch ]
+  br label %inner.loop
+
+inner.loop:
+  %j = phi i64 [ 0, %outer.loop ], [ %j.next, %inner.loop ]
+  %inner.sum = phi i64 [ 0, %outer.loop ], [ %inner.sum.next, %inner.loop ]
+  %prod = mul i64 %i, %j
+  %inner.sum.next = add i64 %inner.sum, %prod
+  %j.next = add i64 %j, 1
+  %inner.cmp = icmp slt i64 %j.next, %m
+  br i1 %inner.cmp, label %inner.loop, label %outer.latch
+
+outer.latch:
+  %new.outer.sum = add i64 %outer.sum, %inner.sum.next
+  %i.next = add i64 %i, 1
+  %outer.cmp = icmp slt i64 %i.next, %n
+  br i1 %outer.cmp, label %outer.loop, label %exit
+
+exit:
+  ret i64 %new.outer.sum
+}
+
+; CHECK:  test_loop_with_invariant
+; CHECK:  bb.0.entry:
+; CHECK:    successors: %bb.1(0x80000000)
+; CHECK:    liveins: $x10, $x11
+;
+; CHECK:    %8:gpr = COPY $x11
+; CHECK:    %7:gpr = COPY $x10
+; CHECK:    %0:gpr = SLLI killed %8, 1
+; CHECK:    %10:gpr = COPY $x0
+; CHECK:    %9:gpr = COPY killed %10
+;
+; CHECK:  bb.1.loop:
+; CHECK:    successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+;
+; CHECK:    %1:gpr = PHI %9, %bb.0, %6, %bb.1
+; CHECK:    %2:gpr = PHI %9, %bb.0, %5, %bb.1
+; CHECK:    %3:gpr = PHI %9, %bb.0, %4, %bb.1
+; CHECK:    %4:gpr = ADD killed %3, %1
+; CHECK:    %5:gpr = ADDI killed %2, 1
+; CHECK:    %6:gpr = ADD killed %1, %0
+; CHECK:    BLT %5, %7, %bb.1
+; CHECK:    PseudoBR %bb.2
+;
+; CHECK:  bb.2.exit:
+; CHECK:    $x10 = COPY killed %4
+; CHECK:    PseudoRET implicit $x10
+
+define i64 @test_loop_with_invariant(i64 %n, i64 %k) {
+entry:
+  %double_k = mul i64 %k, 2
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %sum = phi i64 [ 0, %entry ], [ %sum.next, %loop ]
+  ; double_k is loop-invariant and should be live throughout the loop
+  %scaled = mul i64 %i, %double_k
+  %sum.next = add i64 %sum, %scaled
+  %i.next = add i64 %i, 1
+  %cmp = icmp slt i64 %i.next, %n
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret i64 %sum.next
+}
\ No newline at end of file
diff --git a/llvm/test/CodeGen/RISCV/live-variables-loops.mir b/llvm/test/CodeGen/RISCV/live-variables-loops.mir
deleted file mode 100644
index 1588c65ed0ebf..0000000000000
--- a/llvm/test/CodeGen/RISCV/live-variables-loops.mir
+++ /dev/null
@@ -1,238 +0,0 @@
-# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs -o - %s | FileCheck %s
-#
-# Test live variable analysis with loops and backward edges
-# Loops create interesting liveness patterns with phi nodes and variables
-# that are live across backedges
-
---- |
-  define i64 @test_simple_loop(i64 %n) {
-  entry:
-    br label %loop
-
-  loop:
-    %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
-    %sum = phi i64 [ 0, %entry ], [ %sum.next, %loop ]
-    %sum.next = add i64 %sum, %i
-    %i.next = add i64 %i, 1
-    %cmp = icmp slt i64 %i.next, %n
-    br i1 %cmp, label %loop, label %exit
-
-  exit:
-    ret i64 %sum.next
-  }
-
-  define i64 @test_nested_loop(i64 %n, i64 %m) {
-  entry:
-    br label %outer.loop
-
-  outer.loop:
-    %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
-    %outer.sum = phi i64 [ 0, %entry ], [ %new.outer.sum, %outer.latch ]
-    br label %inner.loop
-
-  inner.loop:
-    %j = phi i64 [ 0, %outer.loop ], [ %j.next, %inner.loop ]
-    %inner.sum = phi i64 [ 0, %outer.loop ], [ %inner.sum.next, %inner.loop ]
-    %prod = mul i64 %i, %j
-    %inner.sum.next = add i64 %inner.sum, %prod
-    %j.next = add i64 %j, 1
-    %inner.cmp = icmp slt i64 %j.next, %m
-    br i1 %inner.cmp, label %inner.loop, label %outer.latch
-
-  outer.latch:
-    %new.outer.sum = add i64 %outer.sum, %inner.sum.next
-    %i.next = add i64 %i, 1
-    %outer.cmp = icmp slt i64 %i.next, %n
-    br i1 %outer.cmp, label %outer.loop, label %exit
-
-  exit:
-    ret i64 %new.outer.sum
-  }
-
-  define i64 @test_loop_with_invariant(i64 %n, i64 %k) {
-  entry:
-    %double_k = mul i64 %k, 2
-    br label %loop
-
-  loop:
-    %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
-    %sum = phi i64 [ 0, %entry ], [ %sum.next, %loop ]
-    ; double_k is loop-invariant and should be live throughout the loop
-    %scaled = mul i64 %i, %double_k
-    %sum.next = add i64 %sum, %scaled
-    %i.next = add i64 %i, 1
-    %cmp = icmp slt i64 %i.next, %n
-    br i1 %cmp, label %loop, label %exit
-
-  exit:
-    ret i64 %sum.next
-  }
-...
----
-name:            test_simple_loop
-alignment:       4
-tracksRegLiveness: true
-registers:
-  - { id: 0, class: gpr }
-  - { id: 1, class: gpr }
-  - { id: 2, class: gpr }
-  - { id: 3, class: gpr }
-  - { id: 4, class: gpr }
-  - { id: 5, class: gpr }
-  - { id: 6, class: gpr }
-  - { id: 7, class: gpr }
-liveins:
-  - { reg: '$x10', virtual-reg: '%0' }
-body:             |
-  bb.0.entry:
-    liveins: $x10
-    ; CHECK-LABEL: name: test_simple_loop
-    ; CHECK: bb.0.entry:
-    ; CHECK-NEXT: successors
-    ; CHECK-NEXT: liveins: $x10
-
-    %0:gpr = COPY $x10
-    %1:gpr = ADDI $x0, 0
-    %2:gpr = ADDI $x0, 0
-    PseudoBR %bb.1
-
-  bb.1.loop:
-    ; CHECK: bb.1.loop:
-    ; %0 should be live-in (used in comparison)
-    ; %1 and %2 should be live-in from backedge or entry
-
-    %3:gpr = PHI %1, %bb.0, %5, %bb.1
-    %4:gpr = PHI %2, %bb.0, %6, %bb.1
-    %6:gpr = ADD %4, %3
-    %5:gpr = ADDI %3, 1
-    %7:gpr = SLT %5, %0
-    BNE %7, $x0, %bb.1
-
-  bb.2.exit:
-    ; CHECK: bb.2.exit:
-    ; %6 should be live-in
-
-    $x10 = COPY %6
-    PseudoRET implicit $x10
-...
----
-name:            test_nested_loop
-alignment:       4
-tracksRegLiveness: true
-registers:
-  - { id: 0, class: gpr }
-  - { id: 1, class: gpr }
-  - { id: 2, class: gpr }
-  - { id: 3, class: gpr }
-  - { id: 4, class: gpr }
-  - { id: 5, class: gpr }
-  - { id: 6, class: gpr }
-  - { id: 7, class: gpr }
-  - { id: 8, class: gpr }
-  - { id: 9, class: gpr }
-  - { id: 10, class: gpr }
-  - { id: 11, class: gpr }
-  - { id: 12, class: gpr }
-  - { id: 13, class: gpr }
-liveins:
-  - { reg: '$x10', virtual-reg: '%0' }
-  - { reg: '$x11', virtual-reg: '%1' }
-body:             |
-  bb.0.entry:
-    liveins: $x10, $x11
-    ; CHECK-LABEL: name: test_nested_loop
-    ; CHECK: bb.0.entry:
-
-    %0:gpr = COPY $x10
-    %1:gpr = COPY $x11
-    %2:gpr = ADDI $x0, 0
-    %3:gpr = ADDI $x0, 0
-    PseudoBR %bb.1
-
-  bb.1.outer.loop:
-    ; CHECK: bb.1.outer.loop:
-    ; %0 and %1 should be live-in (loop bounds)
-
-    %4:gpr = PHI %2, %bb.0, %12, %bb.3
-    %5:gpr = PHI %3, %bb.0, %11, %bb.3
-    %6:gpr = ADDI $x0, 0
-    %7:gpr = ADDI $x0, 0
-    PseudoBR %bb.2
-
-  bb.2.inner.loop:
-    ; CHECK: bb.2.inner.loop:
-    ; %1, %4, %5 should be live-in
-
-    %8:gpr = PHI %6, %bb.1, %13, %bb.2
-    %9:gpr = PHI %7, %bb.1, %10, %bb.2
-    %10:gpr = MUL %4, %8
-    %10:gpr = ADD %9, %10
-    %13:gpr = ADDI %8, 1
-    %14:gpr = SLT %13, %1
-    BNE %14, $x0, %bb.2
-
-  bb.3.outer.latch:
-    ; CHECK: bb.3.outer.latch:
-    ; %0, %5, %10 should be live-in
-
-    %11:gpr = ADD %5, %10
-    %12:gpr = ADDI %4, 1
-    %15:gpr = SLT %12, %0
-    BNE %15, $x0, %bb.1
-
-  bb.4.exit:
-    ; CHECK: bb.4.exit:
-
-    $x10 = COPY %11
-    PseudoRET implicit $x10
-...
----
-name:            test_loop_with_invariant
-alignment:       4
-tracksRegLiveness: true
-registers:
-  - { id: 0, class: gpr }
-  - { id: 1, class: gpr }
-  - { id: 2, class: gpr }
-  - { id: 3, class: gpr }
-  - { id: 4, class: gpr }
-  - { id: 5, class: gpr }
-  - { id: 6, class: gpr }
-  - { id: 7, class: gpr }
-  - { id: 8, class: gpr }
-liveins:
-  - { reg: '$x10', virtual-reg: '%0' }
-  - { reg: '$x11', virtual-reg: '%1' }
-body:             |
-  bb.0.entry:
-    liveins: $x10, $x11
-    ; CHECK-LABEL: name: test_loop_with_invariant
-    ; CHECK: bb.0.entry:
-
-    %0:gpr = COPY $x10
-    %1:gpr = COPY $x11
-    %2:gpr = SLLI %1, 1
-    %3:gpr = ADDI $x0, 0
-    %4:gpr = ADDI $x0, 0
-    PseudoBR %bb.1
-
-  bb.1.loop:
-    ; CHECK: bb.1.loop:
-    ; %0 and %2 should be live-in (loop bound and invariant)
-    ; %2 is computed before loop but used in every iteration
-
-    %5:gpr = PHI %3, %bb.0, %7, %bb.1
-    %6:gpr = PHI %4, %bb.0, %8, %bb.1
-    %9:gpr = MUL %5, %2
-    %8:gpr = ADD %6, %9
-    %7:gpr = ADDI %5, 1
-    %10:gpr = SLT %7, %0
-    BNE %10, $x0, %bb.1
-
-  bb.2.exit:
-    ; CHECK: bb.2.exit:
-
-    $x10 = COPY %8
-    PseudoRET implicit $x10
-...
diff --git a/llvm/test/CodeGen/RISCV/live-variables-rv64.ll b/llvm/test/CodeGen/RISCV/live-variables-rv64.ll
new file mode 100644
index 0000000000000..440337df37f29
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/live-variables-rv64.ll
@@ -0,0 +1,127 @@
+; RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs \
+; RUN: -riscv-enable-live-variables -riscv-liveness-update-kills -stop-after=riscv-live-variables \
+; RUN: -o - %s | FileCheck %s
+
+; Test live variable analysis for RV64-specific scenarios
+; This includes 64-bit operations, wide registers, and RV64-specific instructions
+
+; CHECK:  test_64bit_ops
+; CHECK:  bb.0.entry:
+; CHECK:    liveins: $x10, $x11
+;
+; CHECK:    %1:gpr = COPY $x11
+; CHECK:    %0:gpr = COPY $x10
+; CHECK:    %2:gpr = SLLI killed %0, 32
+; CHECK:    %3:gpr = OR killed %2, killed %1
+; CHECK:    $x10 = COPY killed %3
+; CHECK:    PseudoRET implicit $x10
+
+define i64 @test_64bit_ops(i64 %a, i64 %b) {
+entry:
+  %shl = shl i64 %a, 32
+  %or = or i64 %shl, %b
+  ret i64 %or
+}
+
+; CHECK:  test_word_ops
+; CHECK:  bb.0.entry:
+; CHECK:    liveins: $x10, $x11
+;
+; CHECK:    %1:gpr = COPY $x11
+; CHECK:    %0:gpr = COPY $x10
+; CHECK:    %2:gpr = ADDW killed %0, killed %1
+; CHECK:    $x10 = COPY killed %2
+; CHECK:    PseudoRET implicit $x10
+
+define i64 @test_word_ops(i64 %a, i64 %b) {
+entry:
+  %trunc_a = trunc i64 %a to i32
+  %trunc_b = trunc i64 %b to i32
+  %add = add i32 %trunc_a, %trunc_b
+  %ext = sext i32 %add to i64
+  ret i64 %ext
+}
+
+; CHECK:  test_mixed_width
+; CHECK:  bb.0.entry:
+; CHECK:    liveins: $x10, $x11
+;
+; CHECK:    %1:gpr = COPY $x11
+; CHECK:    %0:gpr = COPY $x10
+; CHECK:    ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:    $x10 = COPY killed %0
+; CHECK:    $x11 = COPY killed %1
+; CHECK:    PseudoCALL target-flags(riscv-call) &__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+; CHECK:    ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:    %2:gpr = COPY $x10
+; CHECK:    %3:gpr = ADDIW killed %2, 0
+; CHECK:    $x10 = COPY killed %3
+; CHECK:    PseudoRET implicit $x10
+
+define i64 @test_mixed_width(i64 %a, i32 %b) {
+entry:
+  %ext_b = sext i32 %b to i64
+  %mul = mul i64 %a, %ext_b
+  %trunc = trunc i64 %mul to i32
+  %final = sext i32 %trunc to i64
+  ret i64 %final
+}
+
+; CHECK:  test_float_64
+; CHECK:  bb.0.entry:
+; CHECK:    successors: %bb.1(0x30000000), %bb.2(0x50000000)
+; CHECK:    liveins: $x10, $x11, $x12
+;
+; CHECK:    %5:gpr = COPY $x12
+; CHECK:    %4:gpr = COPY $x11
+; CHECK:    %3:gpr = COPY $x10
+; CHECK:    %7:gpr = COPY killed %4
+; CHECK:    %6:gpr = COPY killed %3
+; CHECK:    BNE killed %5, $x0, %bb.2
+; CHECK:    PseudoBR %bb.1
+;
+; CHECK:  bb.1.then:
+; CHECK:    successors: %bb.3(0x80000000)
+;
+; CHECK:    ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:    $x10 = COPY killed %6
+; CHECK:    $x11 = COPY killed %7
+; CHECK:    PseudoCALL target-flags(riscv-call) &__adddf3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+; CHECK:    ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:    %9:gpr = COPY $x10
+; CHECK:    %0:gpr = COPY killed %9
+; CHECK:    PseudoBR %bb.3
+;
+; CHECK:  bb.2.else:
+; CHECK:    successors: %bb.3(0x80000000)
+;
+; CHECK:    ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:    $x10 = COPY killed %6
+; CHECK:    $x11 = COPY killed %7
+; CHECK:    PseudoCALL target-flags(riscv-call) &__muldf3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+; CHECK:    ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:    %8:gpr = COPY $x10
+; CHECK:    %1:gpr = COPY killed %8
+;
+; CHECK:  bb.3.end:
+; CHECK:    %2:gpr = PHI %1, %bb.2, %0, %bb.1
+; CHECK:    $x10 = COPY killed %2
+; CHECK:    PseudoRET implicit $x10
+
+define double @test_float_64(double %a, double %b, i64 %selector) {
+entry:
+  %cmp = icmp eq i64 %selector, 0
+  br i1 %cmp, label %then, label %else
+
+then:
+  %add = fadd double %a, %b
+  br label %end
+
+else:
+  %mul = fmul double %a, %b
+  br label %end
+
+end:
+  %result = phi double [ %add, %then ], [ %mul, %else ]
+  ret double %result
+}
\ No newline at end of file
diff --git a/llvm/test/CodeGen/RISCV/live-variables-rv64.mir b/llvm/test/CodeGen/RISCV/live-variables-rv64.mir
deleted file mode 100644
index c3b8ec003a5b6..0000000000000
--- a/llvm/test/CodeGen/RISCV/live-variables-rv64.mir
+++ /dev/null
@@ -1,187 +0,0 @@
-# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs -o - %s | FileCheck %s
-#
-# Test live variable analysis for RV64-specific scenarios
-# This includes 64-bit operations, wide registers, and RV64-specific instructions
-
---- |
-  define i64 @test_64bit_ops(i64 %a, i64 %b) {
-  entry:
-    %shl = shl i64 %a, 32
-    %or = or i64 %shl, %b
-    ret i64 %or
-  }
-
-  define i64 @test_word_ops(i64 %a, i64 %b) {
-  entry:
-    %trunc_a = trunc i64 %a to i32
-    %trunc_b = trunc i64 %b to i32
-    %add = add i32 %trunc_a, %trunc_b
-    %ext = sext i32 %add to i64
-    ret i64 %ext
-  }
-
-  define i64 @test_mixed_width(i64 %a, i32 %b) {
-  entry:
-    %ext_b = sext i32 %b to i64
-    %mul = mul i64 %a, %ext_b
-    %trunc = trunc i64 %mul to i32
-    %final = sext i32 %trunc to i64
-    ret i64 %final
-  }
-
-  define double @test_float_64(double %a, double %b, i64 %selector) {
-  entry:
-    %cmp = icmp eq i64 %selector, 0
-    br i1 %cmp, label %then, label %else
-
-  then:
-    %add = fadd double %a, %b
-    br label %end
-
-  else:
-    %mul = fmul double %a, %b
-    br label %end
-
-  end:
-    %result = phi double [ %add, %then ], [ %mul, %else ]
-    ret double %result
-  }
-...
----
-name:            test_64bit_ops
-alignment:       4
-tracksRegLiveness: true
-registers:
-  - { id: 0, class: gpr }
-  - { id: 1, class: gpr }
-  - { id: 2, class: gpr }
-  - { id: 3, class: gpr }
-liveins:
-  - { reg: '$x10', virtual-reg: '%0' }
-  - { reg: '$x11', virtual-reg: '%1' }
-body:             |
-  bb.0.entry:
-    liveins: $x10, $x11
-    ; CHECK-LABEL: name: test_64bit_ops
-    ; CHECK: bb.0.entry:
-    ; CHECK-NEXT: liveins: $x10, $x11
-    ; Test 64-bit shift and or operations
-
-    %0:gpr = COPY $x10
-    %1:gpr = COPY $x11
-    %2:gpr = SLLI %0, 32
-    %3:gpr = OR %2, %1
-    %4:gpr = COPY %3
-    PseudoRET implicit $x10
-...
----
-name:            test_word_ops
-alignment:       4
-tracksRegLiveness: true
-registers:
-  - { id: 0, class: gpr }
-  - { id: 1, class: gpr }
-  - { id: 2, class: gpr }
-liveins:
-  - { reg: '$x10', virtual-reg: '%0' }
-  - { reg: '$x11', virtual-reg: '%1' }
-body:             |
-  bb.0.entry:
-    liveins: $x10, $x11
-    ; CHECK-LABEL: name: test_word_ops
-    ; CHECK: bb.0.entry:
-    ; CHECK-NEXT: liveins: $x10, $x11
-    ; Test RV64 W-suffix instructions (32-bit ops on 64-bit regs)
-
-    %0:gpr = COPY $x10
-    %1:gpr = COPY $x11
-    ; ADDW is RV64-specific: 32-bit add with sign-extension
-    %2:gpr = ADDW %0, %1
-    $x10 = COPY %2
-    PseudoRET implicit $x10
-...
----
-name:            test_mixed_width
-alignment:       4
-tracksRegLiveness: true
-registers:
-  - { id: 0, class: gpr }
-  - { id: 1, class: gpr }
-  - { id: 2, class: gpr }
-  - { id: 3, class: gpr }
-  - { id: 4, class: gpr }
-liveins:
-  - { reg: '$x10', virtual-reg: '%0' }
-  - { reg: '$x11_w', virtual-reg: '%1' }
-body:             |
-  bb.0.entry:
-    liveins: $x10, $x11_w
-    ; CHECK-LABEL: name: test_mixed_width
-    ; CHECK: bb.0.entry:
-    ; CHECK-NEXT: liveins: $x10, $x11_w
-    ; Test mixed 32/64-bit operations
-
-    %0:gpr = COPY $x10
-    ; Sign-extend 32-bit value to 64-bit
-    %1:gpr = COPY $x11_w
-    %2:gpr = ADDIW %1, 0
-    %3:gpr = MUL %0, %2
-    ; Extract lower 32 bits and sign-extend
-    %4:gpr = ADDIW %3, 0
-    $x10 = COPY %4
-    PseudoRET implicit $x10
-...
----
-name:            test_float_64
-alignment:       4
-tracksRegLiveness: true
-registers:
-  - { id: 0, class: fpr64 }
-  - { id: 1, class: fpr64 }
-  - { id: 2, class: gpr }
-  - { id: 3, class: gpr }
-  - { id: 4, class: fpr64 }
-  - { id: 5, class: fpr64 }
-  - { id: 6, class: fpr64 }
-liveins:
-  - { reg: '$f10_d', virtual-reg: '%0' }
-  - { reg: '$f11_d', virtual-reg: '%1' }
-  - { reg: '$x10', virtual-reg: '%2' }
-body:             |
-  bb.0.entry:
-    liveins: $f10_d, $f11_d, $x10
-    ; CHECK-LABEL: name: test_float_64
-    ; CHECK: bb.0.entry:
-    ; CHECK-NEXT: successors
-    ; CHECK-NEXT: liveins: $f10_d, $f11_d, $x10
-    ; Test 64-bit floating point register liveness
-
-    %0:fpr64 = COPY $f10_d
-    %1:fpr64 = COPY $f11_d
-    %2:gpr = COPY $x10
-    %3:gpr = ADDI $x0, 0
-    BNE %2, %3, %bb.2
-
-  bb.1.then:
-    ; CHECK: bb.1.then:
-    ; %0 and %1 should be live-in (FP registers)
-
-    %4:fpr64 = FADD_D %0, %1, 7
-    PseudoBR %bb.3
-
-  bb.2.else:
-    ; CHECK: bb.2.else:
-    ; %0 and %1 should be live-in
-
-    %5:fpr64 = FMUL_D %0, %1, 7
-    PseudoBR %bb.3
-
-  bb.3.end:
-    ; CHECK: bb.3.end:
-    ; Either %4 or %5 should be live-in
-
-    %6:fpr64 = PHI %4, %bb.1, %5, %bb.2
-    $f10_d = COPY %6
-    PseudoRET implicit $f10_d
-...

>From b8e06ff93d9c95286e7cc235704fd9c38a407f33 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sun, 16 Nov 2025 12:25:26 -0800
Subject: [PATCH 12/32] Update test to check loop invariant motion

---
 .../RISCV/live-variables-pre-regalloc.ll      | 25 +++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/live-variables-pre-regalloc.ll b/llvm/test/CodeGen/RISCV/live-variables-pre-regalloc.ll
index c3465b07dd65c..bed71de0d3337 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-pre-regalloc.ll
+++ b/llvm/test/CodeGen/RISCV/live-variables-pre-regalloc.ll
@@ -1,8 +1,29 @@
-; RUN: llc -mtriple riscv64 -mattr=+d -riscv-enable-live-variables --stop-after=riscv-live-variables -riscv-liveness-update-kills < %s | FileCheck %s
+; RUN: llc -mtriple riscv64 -mattr=+d -riscv-enable-live-variables \
+; RUN: --stop-after=riscv-live-variables -riscv-liveness-update-kills < %s | FileCheck %s
+
+; RUN: llc -mtriple riscv64 -mattr=+d -riscv-enable-live-variables \
+; RUN: -riscv-liveness-update-kills < %s | FileCheck --check-prefix=CHECK-LICM %s
 
 ; Issue: #166141 Pessimistic MachineLICM due to missing liveness info.
 
-; CHECK: %42:fpr64 = nofpexcept FMUL_D killed %2, killed %41, 7, implicit $frm
+; Check that live variable analysis correctly marks %41 as kill
+; CHECK:  bb.2.if:
+; CHECK:    successors: %bb.3(0x80000000)
+;
+; CHECK:    %40:gpr = LUI target-flags(riscv-hi) %const.0
+; CHECK:    %41:fpr64 = FLD killed %40, target-flags(riscv-lo) %const.0 :: (load (s64) from constant-pool)
+; CHECK:    %42:fpr64 = nofpexcept FMUL_D killed %2, killed %41, 7, implicit $frm
+; CHECK:    FSD killed %42, %1, 0 :: (store (s64) into %ir.lsr.iv1)
+
+; Check that the loop invariant `fld` is hoisted out of the loop.
+; CHECK-LICM: # %bb.0:
+; CHECK-LICM:        lui     a1, %hi(.LCPI0_0)
+; CHECK-LICM:        fld     fa5, %lo(.LCPI0_0)(a1)
+; CHECK-LICM:        lui     a1, 2
+; CHECK-LICM:        add     a1, a0, a1
+; CHECK-LICM:        fmv.d.x fa4, zero
+; CHECK-LICM:        j       .LBB0_2
+; CHECK-LICM: .LBB0_1:
 
 define void @f(ptr %p) {
 entry:

>From cd293daa8ca4b5f60951abef5b09eb231b67de06 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sun, 16 Nov 2025 12:29:34 -0800
Subject: [PATCH 13/32] Comment

---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp  | 36 +++++++++----------
 .../CodeGen/RISCV/live-variables-loops.ll     |  2 +-
 2 files changed, 17 insertions(+), 21 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index 79397836d1bae..6598db336aa12 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -10,11 +10,9 @@
 // The pass computes liveness information for virtual and physical registers
 // in RISC-V machine functions, optimized for RV64 (64-bit RISC-V architecture).
 //
-// The analysis performs a backward dataflow analysis to compute:
-// - Live-in sets: Registers that are live at the entry of a basic block
-// - Live-out sets: Registers that are live at the exit of a basic block
-// - Kill points: Instructions where a register's last use occurs
-// - Def points: Instructions where a register is defined
+// The analysis performs a backward dataflow analysis to compute
+// liveness information. Also updates the kill flags on register operands.
+// There is also a verification step to ensure consistency with MBB live-ins.
 //
 //===----------------------------------------------------------------------===//
 
@@ -50,6 +48,10 @@ static cl::opt<bool> UpdateKills("riscv-liveness-update-kills",
                                  cl::desc("Update kill flags"), cl::init(false),
                                  cl::Hidden);
 
+static cl::opt<unsigned> MaxVRegs("riscv-liveness-max-vregs",
+                                  cl::desc("Maximum VRegs to track"),
+                                  cl::init(1024), cl::Hidden);
+
 namespace {
 
 /// LivenessInfo - Stores liveness information for a basic block
@@ -158,21 +160,16 @@ FunctionPass *llvm::createRISCVLiveVariablesPass(bool PreRegAlloc) {
 bool RISCVLiveVariables::isTrackableRegister(
     Register Reg, const TargetRegisterInfo *TRI,
     const MachineRegisterInfo *MRI) const {
-  // Track virtual registers
+  // Track all virtual registers but only allocatable physical registers.
+  // 1. General purpose registers (X0-X31)
+  // 2. Floating point registers (F0-F31)
+  // 3. Vector registers if present
+
   if (Reg.isVirtual())
     return true;
 
-  // For physical registers, only track allocatable ones
-  if (Reg.isPhysical()) {
-    // Check if register is allocatable
-    if (!TRI->isInAllocatableClass(Reg))
-      return false;
-
-    // Track general purpose registers (X0-X31)
-    // Track floating point registers (F0-F31)
-    // Track vector registers for RVV if present
-    return true;
-  }
+  if (Reg.isPhysical())
+    return TRI->isInAllocatableClass(Reg);
 
   return false;
 }
@@ -194,8 +191,7 @@ void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
       continue;
 
     if (MO.isUse()) {
-      // This is a use - only add to Use set if not already defined in this
-      // block
+      // Only add to Use set if not already defined in this block.
       if (Info.Gen.find(Reg) == Info.Gen.end()) {
         Info.Use.insert(Reg);
 
@@ -477,7 +473,7 @@ bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
   // TODO: Update live-in/live-out sets of MBBs
 
   // Step 3: Mark kill flags on operands
-  if (UpdateKills)
+  if (UpdateKills && MaxVRegs >= RegCounter)
     markKills(MF);
 
   LLVM_DEBUG({
diff --git a/llvm/test/CodeGen/RISCV/live-variables-loops.ll b/llvm/test/CodeGen/RISCV/live-variables-loops.ll
index a689846baccbd..2cc0ff65c74b3 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-loops.ll
+++ b/llvm/test/CodeGen/RISCV/live-variables-loops.ll
@@ -159,4 +159,4 @@ loop:
 
 exit:
   ret i64 %sum.next
-}
\ No newline at end of file
+}

>From e5cbfc875701ebeb6cc8ce3f8092f26f34ffb12e Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Mon, 17 Nov 2025 20:25:53 -0800
Subject: [PATCH 14/32] Return true when kill information is updated

---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index 6598db336aa12..560a21d2b9598 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -112,7 +112,7 @@ class RISCVLiveVariables : public MachineFunctionPass {
   void verifyLiveness(MachineFunction &MF) const;
 
   /// Mark operands that kill a register
-  void markKills(MachineFunction &MF);
+  bool markKills(MachineFunction &MF);
 
 private:
   /// Compute local liveness information (Use and Def sets) for each block
@@ -380,7 +380,8 @@ void RISCVLiveVariables::verifyLiveness(MachineFunction &MF) const {
   }
 }
 
-void RISCVLiveVariables::markKills(MachineFunction &MF) {
+bool RISCVLiveVariables::markKills(MachineFunction &MF) {
+  bool Changed = false;
   auto KillSetSize = PreRegAlloc ? RegCounter : TRI->getNumRegs();
   for (MachineBasicBlock *MBB : post_order(&MF)) {
     // Set all the registers that are not live-out of the block.
@@ -427,8 +428,10 @@ void RISCVLiveVariables::markKills(MachineFunction &MF) {
         auto RegIdx = PreRegAlloc ? TrackedRegisters[Reg] : Reg.asMCReg().id();
 
         if (KillSet[RegIdx]) {
-          if (!MO.isKill() && !MI.isPHI())
+          if (!MO.isKill() && !MI.isPHI()) {
             MO.setIsKill(true);
+            Changed = true;
+          }
           LLVM_DEBUG(dbgs() << "Marking kill of " << printReg(Reg, TRI)
                             << " at instruction: " << MI);
           KillSet.reset(RegIdx);
@@ -440,6 +443,7 @@ void RISCVLiveVariables::markKills(MachineFunction &MF) {
       }
     }
   }
+  return Changed;
 }
 
 bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
@@ -472,9 +476,10 @@ bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
 
   // TODO: Update live-in/live-out sets of MBBs
 
+  bool Changed = false;
   // Step 3: Mark kill flags on operands
   if (UpdateKills && MaxVRegs >= RegCounter)
-    markKills(MF);
+    Changed = markKills(MF);
 
   LLVM_DEBUG({
     dbgs() << "\n***** Final Liveness Information *****\n";
@@ -483,7 +488,7 @@ bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
 
   verifyLiveness(MF);
   // This is an analysis pass, it doesn't modify the function
-  return false;
+  return Changed;
 }
 
 void RISCVLiveVariables::print(raw_ostream &OS, const Module *M) const {

>From ef3a9612e04164d01eac460e760eab971107c753 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Mon, 17 Nov 2025 20:28:48 -0800
Subject: [PATCH 15/32] Add a flag to disable verification

---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index 560a21d2b9598..7d63873874ee0 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -52,6 +52,10 @@ static cl::opt<unsigned> MaxVRegs("riscv-liveness-max-vregs",
                                   cl::desc("Maximum VRegs to track"),
                                   cl::init(1024), cl::Hidden);
 
+static cl::opt<unsigned> VerifyLiveness("riscv-liveness-verify",
+                                        cl::desc("Verify liveness information"),
+                                        cl::init(true), cl::Hidden);
+
 namespace {
 
 /// LivenessInfo - Stores liveness information for a basic block
@@ -109,9 +113,12 @@ class RISCVLiveVariables : public MachineFunctionPass {
   /// Print liveness information for debugging
   void print(raw_ostream &OS, const Module *M = nullptr) const override;
 
+  /// Verify the computed liveness information against MBB live-ins.
+  /// TODO: Extend verification to live-outs and instruction-level liveness.
   void verifyLiveness(MachineFunction &MF) const;
 
   /// Mark operands that kill a register
+  /// TODO: Add and remove kill flags as necessary.
   bool markKills(MachineFunction &MF);
 
 private:
@@ -486,8 +493,9 @@ bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
     print(dbgs());
   });
 
-  verifyLiveness(MF);
-  // This is an analysis pass, it doesn't modify the function
+  if (VerifyLiveness)
+    verifyLiveness(MF);
+
   return Changed;
 }
 

>From e48964a60b746df1daeb5651aba36243848b9b5b Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Wed, 19 Nov 2025 20:38:44 -0800
Subject: [PATCH 16/32] Update live-in set of basic blocks

---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp  |  61 ++-
 .../RISCV/live-variables-mbb-liveins.ll       | 362 ++++++++++++++++++
 2 files changed, 421 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index 7d63873874ee0..42529d1daa488 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -128,6 +128,9 @@ class RISCVLiveVariables : public MachineFunctionPass {
   /// Compute global liveness information (LiveIn and LiveOut sets)
   void computeGlobalLiveness(MachineFunction &MF);
 
+  /// Update MBB live-in sets based on computed liveness information
+  void updateMBBLiveIns(MachineFunction &MF);
+
   /// Process a single instruction to extract def/use information
   void processInstruction(const MachineInstr &MI, LivenessInfo &Info,
                           const TargetRegisterInfo *TRI);
@@ -345,6 +348,59 @@ void RISCVLiveVariables::computeGlobalLiveness(MachineFunction &MF) {
   }
 }
 
+void RISCVLiveVariables::updateMBBLiveIns(MachineFunction &MF) {
+  LLVM_DEBUG(dbgs() << "Updating MBB live-in sets\n");
+
+  // Update each MBB's live-in set based on computed liveness
+  // Only update physical register live-ins, as MBB live-in sets
+  // track physical registers entering a block
+  for (MachineBasicBlock &MBB : MF) {
+    auto It = BlockLiveness.find(&MBB);
+    if (It == BlockLiveness.end())
+      continue;
+
+    const LivenessInfo &Info = It->second;
+
+    // Clear existing live-ins
+    MBB.clearLiveIns();
+
+    // Add computed live-in physical registers to the MBB
+    // Skip sub-registers - only add top-level registers
+    // Also skip reserved registers (stack pointer, zero register, etc.)
+    for (Register Reg : Info.LiveIn) {
+      if (Reg.isPhysical()) {
+        MCRegister MCReg = Reg.asMCReg();
+
+        // Skip reserved registers - they're implicitly always live
+        if (MRI->isReserved(Reg))
+          continue;
+
+        // Only add if this is not a sub-register of another register
+        // We want top-level registers only (e.g., $x10, not $x10_w)
+        bool IsSubReg = false;
+        for (MCSuperRegIterator SR(MCReg, TRI, /*IncludeSelf=*/false);
+             SR.isValid(); ++SR) {
+          if (Info.LiveIn.count(Register(*SR))) {
+            IsSubReg = true;
+            break;
+          }
+        }
+
+        if (!IsSubReg) {
+          MBB.addLiveIn(MCReg);
+          LLVM_DEBUG(dbgs() << "  Adding live-in " << printReg(Reg, TRI)
+                            << " to block " << MBB.getName() << "\n");
+        }
+      }
+    }
+
+    // Sort and unique the live-ins for efficient lookup
+    MBB.sortUniqueLiveIns();
+  }
+
+  LLVM_DEBUG(dbgs() << "MBB live-in sets updated\n");
+}
+
 bool RISCVLiveVariables::isLiveAt(Register Reg, const MachineInstr &MI) const {
   const MachineBasicBlock *MBB = MI.getParent();
   auto It = BlockLiveness.find(MBB);
@@ -481,10 +537,11 @@ bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
   // Step 2: Compute global liveness (LiveIn and LiveOut sets)
   computeGlobalLiveness(MF);
 
-  // TODO: Update live-in/live-out sets of MBBs
+  // Step 3: Update live-in sets of MBBs based on computed liveness
+  updateMBBLiveIns(MF);
 
   bool Changed = false;
-  // Step 3: Mark kill flags on operands
+  // Step 4: Mark kill flags on operands
   if (UpdateKills && MaxVRegs >= RegCounter)
     Changed = markKills(MF);
 
diff --git a/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll b/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll
new file mode 100644
index 0000000000000..199fdf734488b
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll
@@ -0,0 +1,362 @@
+; RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs \
+; RUN: -riscv-liveness-update-kills -stop-after=riscv-live-variables \
+; RUN: -o - %s | FileCheck %s
+
+; Test that updateMBBLiveIns correctly updates the live-in sets of basic blocks
+
+; Basic test: simple function with two arguments
+; CHECK-LABEL: name: test_mbb_liveins
+; CHECK: bb.0.entry:
+; CHECK:   liveins: $x10, $x11
+; CHECK:   %1:gpr = COPY $x11
+; CHECK:   %0:gpr = COPY $x10
+; CHECK:   %2:gpr = ADD killed %0, killed %1
+; CHECK:   $x10 = COPY killed %2
+; CHECK:   PseudoRET implicit $x10
+
+define i64 @test_mbb_liveins(i64 %a, i64 %b) {
+entry:
+  %sum = add i64 %a, %b
+  ret i64 %sum
+}
+
+; Test with control flow: verify live-ins are correct for entry block with multiple args
+; CHECK-LABEL: name: test_control_flow
+; CHECK: bb.0.entry:
+; CHECK:   liveins: $x10, $x11, $x12
+
+define i64 @test_control_flow(i64 %a, i64 %b, i64 %cond) {
+entry:
+  %cmp = icmp eq i64 %cond, 0
+  br i1 %cmp, label %then, label %else
+
+then:
+  %add = add i64 %a, %b
+  br label %end
+
+else:
+  %sub = sub i64 %a, %b
+  br label %end
+
+end:
+  %result = phi i64 [ %add, %then ], [ %sub, %else ]
+  ret i64 %result
+}
+
+; Test with loops: verify live-ins for loop headers
+; CHECK-LABEL: name: test_loop
+; CHECK: bb.0.entry:
+; CHECK:   liveins: $x10
+; CHECK: bb.1.loop:
+; CHECK: bb.2.exit:
+
+define i64 @test_loop(i64 %n) {
+entry:
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %next, %loop ]
+  %next = add i64 %i, 1
+  %cmp = icmp ult i64 %next, %n
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret i64 %next
+}
+
+; Test that reserved registers (like $x2 stack pointer) are NOT in live-ins
+; This test uses function calls which implicitly use $x2 for stack operations
+; CHECK-LABEL: name: test_reserved_regs
+; CHECK: bb.0.entry:
+; CHECK:   liveins: $x10, $x11
+; CHECK-NOT:   liveins: {{.*}}$x2
+; CHECK:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+; CHECK:   $x10 = COPY killed %0
+; CHECK:   $x11 = COPY killed %1
+; CHECK:   PseudoCALL target-flags(riscv-call) @__adddi3
+
+define i64 @test_reserved_regs(i64 %a, i64 %b) {
+entry:
+  %sum = call i64 @__adddi3(i64 %a, i64 %b)
+  ret i64 %sum
+}
+
+declare i64 @__adddi3(i64, i64)
+
+; Test with multiple arguments to verify all live-ins are tracked
+; CHECK-LABEL: name: test_many_args
+; CHECK: bb.0.entry:
+; CHECK:   liveins: $x10, $x11, $x12, $x13
+; CHECK:   %3:gpr = COPY $x13
+; CHECK:   %2:gpr = COPY $x12
+; CHECK:   %1:gpr = COPY $x11
+; CHECK:   %0:gpr = COPY $x10
+
+define i64 @test_many_args(i64 %a, i64 %b, i64 %c, i64 %d) {
+entry:
+  %sum1 = add i64 %a, %b
+  %sum2 = add i64 %c, %d
+  %result = add i64 %sum1, %sum2
+  ret i64 %result
+}
+
+; Test with nested control flow to ensure entry block has correct live-ins
+; CHECK-LABEL: name: test_nested_control_flow
+; CHECK: bb.0.entry:
+; CHECK:   liveins: $x10, $x11, $x12
+
+define i64 @test_nested_control_flow(i64 %a, i64 %b, i64 %c) {
+entry:
+  %cmp1 = icmp eq i64 %c, 0
+  br i1 %cmp1, label %outer_then, label %outer_else
+
+outer_then:
+  %cmp2 = icmp sgt i64 %a, %b
+  br i1 %cmp2, label %inner_then, label %inner_else
+
+inner_then:
+  %add = add i64 %a, %b
+  br label %end
+
+inner_else:
+  %sub = sub i64 %a, %b
+  br label %end
+
+outer_else:
+  %mul = mul i64 %a, 2
+  br label %end
+
+end:
+  %result = phi i64 [ %add, %inner_then ], [ %sub, %inner_else ], [ %mul, %outer_else ]
+  ret i64 %result
+}
+
+; Test with doubly nested loops
+; CHECK-LABEL: name: test_doubly_nested_loop
+; CHECK: bb.0.entry:
+; CHECK:   liveins: $x10, $x11
+
+define i64 @test_doubly_nested_loop(i64 %n, i64 %m) {
+entry:
+  br label %outer_loop
+
+outer_loop:
+  %i = phi i64 [ 0, %entry ], [ %i_next, %outer_latch ]
+  %sum_outer = phi i64 [ 0, %entry ], [ %sum_final, %outer_latch ]
+  %i_cmp = icmp ult i64 %i, %n
+  br i1 %i_cmp, label %inner_loop, label %exit
+
+inner_loop:
+  %j = phi i64 [ 0, %outer_loop ], [ %j_next, %inner_loop ]
+  %sum_inner = phi i64 [ %sum_outer, %outer_loop ], [ %sum_new, %inner_loop ]
+  %sum_new = add i64 %sum_inner, %j
+  %j_next = add i64 %j, 1
+  %j_cmp = icmp ult i64 %j_next, %m
+  br i1 %j_cmp, label %inner_loop, label %outer_latch
+
+outer_latch:
+  %sum_final = phi i64 [ %sum_new, %inner_loop ]
+  %i_next = add i64 %i, 1
+  br label %outer_loop
+
+exit:
+  ret i64 %sum_outer
+}
+
+; Test with triply nested loops and function calls
+; This tests that reserved registers ($x2) are not added to live-ins even with deep nesting
+; CHECK-LABEL: name: test_triply_nested_loop_with_calls
+; CHECK: bb.0.entry:
+; CHECK:   liveins: $x10, $x11, $x12
+; CHECK-NOT:   liveins: {{.*}}$x2
+
+define i64 @test_triply_nested_loop_with_calls(i64 %n, i64 %m, i64 %p) {
+entry:
+  br label %loop_i
+
+loop_i:
+  %i = phi i64 [ 0, %entry ], [ %i_next, %loop_i_latch ]
+  %sum_i = phi i64 [ 0, %entry ], [ %sum_after_j, %loop_i_latch ]
+  %i_cmp = icmp ult i64 %i, %n
+  br i1 %i_cmp, label %loop_j_header, label %exit
+
+loop_j_header:
+  br label %loop_j
+
+loop_j:
+  %j = phi i64 [ 0, %loop_j_header ], [ %j_next, %loop_j_latch ]
+  %sum_j = phi i64 [ %sum_i, %loop_j_header ], [ %sum_after_k, %loop_j_latch ]
+  %j_cmp = icmp ult i64 %j, %m
+  br i1 %j_cmp, label %loop_k_header, label %loop_j_exit
+
+loop_k_header:
+  br label %loop_k
+
+loop_k:
+  %k = phi i64 [ 0, %loop_k_header ], [ %k_next, %loop_k ]
+  %sum_k = phi i64 [ %sum_j, %loop_k_header ], [ %sum_k_new, %loop_k ]
+
+  ; Function call inside innermost loop - uses stack pointer $x2 implicitly
+  %prod = call i64 @__muldi3(i64 %i, i64 %j)
+  %sum_k_new = add i64 %sum_k, %prod
+
+  %k_next = add i64 %k, 1
+  %k_cmp = icmp ult i64 %k_next, %p
+  br i1 %k_cmp, label %loop_k, label %loop_k_exit
+
+loop_k_exit:
+  br label %loop_j_latch
+
+loop_j_latch:
+  %sum_after_k = phi i64 [ %sum_k_new, %loop_k_exit ]
+  %j_next = add i64 %j, 1
+  br label %loop_j
+
+loop_j_exit:
+  br label %loop_i_latch
+
+loop_i_latch:
+  %sum_after_j = phi i64 [ %sum_j, %loop_j_exit ]
+  %i_next = add i64 %i, 1
+  br label %loop_i
+
+exit:
+  ret i64 %sum_i
+}
+
+declare i64 @__muldi3(i64, i64)
+
+; Test with unstructured control flow (multiple entries, irreducible loop)
+; CHECK-LABEL: name: test_unstructured_cfg
+; CHECK: bb.0.entry:
+; CHECK:   liveins: $x10, $x11, $x12
+
+define i64 @test_unstructured_cfg(i64 %a, i64 %b, i64 %selector) {
+entry:
+  %cmp1 = icmp eq i64 %selector, 0
+  br i1 %cmp1, label %block_a, label %block_b
+
+block_a:
+  %val_a = add i64 %a, 1
+  %cmp_a = icmp slt i64 %val_a, 10
+  br i1 %cmp_a, label %block_b, label %block_c
+
+block_b:
+  %phi_b = phi i64 [ %b, %entry ], [ %val_a, %block_a ], [ %val_c, %block_c ]
+  %val_b = mul i64 %phi_b, 2
+  %cmp_b = icmp sgt i64 %val_b, 100
+  br i1 %cmp_b, label %exit, label %block_c
+
+block_c:
+  %phi_c = phi i64 [ %val_a, %block_a ], [ %val_b, %block_b ]
+  %val_c = sub i64 %phi_c, 1
+  %cmp_c = icmp ugt i64 %val_c, 5
+  br i1 %cmp_c, label %block_b, label %block_a
+
+exit:
+  %result = phi i64 [ %val_b, %block_b ]
+  ret i64 %result
+}
+
+; Test with multiple function calls and complex control flow
+; Ensures reserved registers are not in live-ins across multiple call sites
+; CHECK-LABEL: name: test_multiple_calls
+; CHECK: bb.0.entry:
+; CHECK:   liveins: $x10, $x11, $x12, $x13
+; CHECK-NOT:   liveins: {{.*}}$x2
+
+define i64 @test_multiple_calls(i64 %a, i64 %b, i64 %c, i64 %d) {
+entry:
+  %cmp = icmp sgt i64 %a, %b
+  br i1 %cmp, label %call1, label %call2
+
+call1:
+  %res1 = call i64 @__adddi3(i64 %a, i64 %b)
+  %cmp1 = icmp eq i64 %res1, 0
+  br i1 %cmp1, label %call3, label %merge
+
+call2:
+  %res2 = call i64 @__muldi3(i64 %c, i64 %d)
+  br label %merge
+
+call3:
+  %res3 = call i64 @__adddi3(i64 %c, i64 %d)
+  br label %merge
+
+merge:
+  %final = phi i64 [ %res1, %call1 ], [ %res2, %call2 ], [ %res3, %call3 ]
+  ret i64 %final
+}
+
+; Test with switch-like control flow
+; CHECK-LABEL: name: test_switch_cfg
+; CHECK: bb.0.entry:
+; CHECK:   liveins: $x10, $x11
+
+define i64 @test_switch_cfg(i64 %selector, i64 %value) {
+entry:
+  switch i64 %selector, label %default [
+    i64 0, label %case0
+    i64 1, label %case1
+    i64 2, label %case2
+    i64 3, label %case3
+  ]
+
+case0:
+  %res0 = add i64 %value, 10
+  br label %exit
+
+case1:
+  %res1 = sub i64 %value, 10
+  br label %exit
+
+case2:
+  %res2 = mul i64 %value, 2
+  br label %exit
+
+case3:
+  %res3 = shl i64 %value, 1
+  br label %exit
+
+default:
+  br label %exit
+
+exit:
+  %result = phi i64 [ %res0, %case0 ], [ %res1, %case1 ], [ %res2, %case2 ], [ %res3, %case3 ], [ 0, %default ]
+  ret i64 %result
+}
+
+; Test with loop with multiple exits
+; CHECK-LABEL: name: test_loop_multiple_exits
+; CHECK: bb.0.entry:
+; CHECK:   liveins: $x10, $x11, $x12
+
+define i64 @test_loop_multiple_exits(i64 %n, i64 %threshold, i64 %increment) {
+entry:
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i_next, %loop_continue ]
+  %sum = phi i64 [ 0, %entry ], [ %sum_next, %loop_continue ]
+
+  ; Check for exit condition 1
+  %cmp1 = icmp ugt i64 %sum, %threshold
+  br i1 %cmp1, label %exit1, label %check2
+
+check2:
+  ; Check for exit condition 2
+  %cmp2 = icmp ugt i64 %i, %n
+  br i1 %cmp2, label %exit2, label %loop_continue
+
+loop_continue:
+  %sum_next = add i64 %sum, %increment
+  %i_next = add i64 %i, 1
+  br label %loop
+
+exit1:
+  ret i64 %sum
+
+exit2:
+  %final = mul i64 %sum, 2
+  ret i64 %final
+}
\ No newline at end of file

>From 84d53183bd1be488d4fe8a86ec7e8ffd60f2ea32 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Wed, 19 Nov 2025 21:20:34 -0800
Subject: [PATCH 17/32] Add a flag to gate update of live-in set

---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp  | 22 +++++++++-------
 .../RISCV/live-variables-mbb-liveins.ll       | 25 ++++++++++++++++++-
 2 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index 42529d1daa488..2af52b9c573f0 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -48,6 +48,10 @@ static cl::opt<bool> UpdateKills("riscv-liveness-update-kills",
                                  cl::desc("Update kill flags"), cl::init(false),
                                  cl::Hidden);
 
+static cl::opt<bool> UpdateLiveIns("riscv-liveness-update-mbb-liveins",
+                                   cl::desc("Update MBB live-in sets"),
+                                   cl::init(false), cl::Hidden);
+
 static cl::opt<unsigned> MaxVRegs("riscv-liveness-max-vregs",
                                   cl::desc("Maximum VRegs to track"),
                                   cl::init(1024), cl::Hidden);
@@ -129,7 +133,7 @@ class RISCVLiveVariables : public MachineFunctionPass {
   void computeGlobalLiveness(MachineFunction &MF);
 
   /// Update MBB live-in sets based on computed liveness information
-  void updateMBBLiveIns(MachineFunction &MF);
+  bool updateMBBLiveIns(MachineFunction &MF);
 
   /// Process a single instruction to extract def/use information
   void processInstruction(const MachineInstr &MI, LivenessInfo &Info,
@@ -348,18 +352,18 @@ void RISCVLiveVariables::computeGlobalLiveness(MachineFunction &MF) {
   }
 }
 
-void RISCVLiveVariables::updateMBBLiveIns(MachineFunction &MF) {
-  LLVM_DEBUG(dbgs() << "Updating MBB live-in sets\n");
-
+bool RISCVLiveVariables::updateMBBLiveIns(MachineFunction &MF) {
   // Update each MBB's live-in set based on computed liveness
   // Only update physical register live-ins, as MBB live-in sets
   // track physical registers entering a block
+  bool Changed = false;
   for (MachineBasicBlock &MBB : MF) {
     auto It = BlockLiveness.find(&MBB);
     if (It == BlockLiveness.end())
       continue;
 
     const LivenessInfo &Info = It->second;
+    Changed = true;
 
     // Clear existing live-ins
     MBB.clearLiveIns();
@@ -397,8 +401,7 @@ void RISCVLiveVariables::updateMBBLiveIns(MachineFunction &MF) {
     // Sort and unique the live-ins for efficient lookup
     MBB.sortUniqueLiveIns();
   }
-
-  LLVM_DEBUG(dbgs() << "MBB live-in sets updated\n");
+  return Changed;
 }
 
 bool RISCVLiveVariables::isLiveAt(Register Reg, const MachineInstr &MI) const {
@@ -537,13 +540,14 @@ bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
   // Step 2: Compute global liveness (LiveIn and LiveOut sets)
   computeGlobalLiveness(MF);
 
+  bool Changed = false;
   // Step 3: Update live-in sets of MBBs based on computed liveness
-  updateMBBLiveIns(MF);
+  if (UpdateLiveIns)
+    Changed = updateMBBLiveIns(MF);
 
-  bool Changed = false;
   // Step 4: Mark kill flags on operands
   if (UpdateKills && MaxVRegs >= RegCounter)
-    Changed = markKills(MF);
+    Changed |= markKills(MF);
 
   LLVM_DEBUG({
     dbgs() << "\n***** Final Liveness Information *****\n";
diff --git a/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll b/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll
index 199fdf734488b..f553e75931e48 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll
+++ b/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll
@@ -1,6 +1,6 @@
 ; RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs \
 ; RUN: -riscv-liveness-update-kills -stop-after=riscv-live-variables \
-; RUN: -o - %s | FileCheck %s
+; RUN: -riscv-liveness-update-mbb-liveins < %s | FileCheck %s
 
 ; Test that updateMBBLiveIns correctly updates the live-in sets of basic blocks
 
@@ -23,7 +23,28 @@ entry:
 ; Test with control flow: verify live-ins are correct for entry block with multiple args
 ; CHECK-LABEL: name: test_control_flow
 ; CHECK: bb.0.entry:
+; CHECK:   successors: %bb.1(0x30000000), %bb.2(0x50000000); %bb.1(37.50%), %bb.2(62.50%)
 ; CHECK:   liveins: $x10, $x11, $x12
+; CHECK:   BNE killed renamable $x12, killed $x0, %bb.2
+; CHECK:   PseudoBR %bb.1
+; CHECK:
+; CHECK: bb.1.then:
+; CHECK: ; predecessors: %bb.0
+; CHECK:   successors: %bb.3(0x80000000); %bb.3(100.00%)
+; CHECK:   liveins: $x10, $x11
+; CHECK:   renamable $x10 = ADD killed renamable $x10, killed renamable $x11
+; CHECK:   PseudoBR %bb.3
+; CHECK:
+; CHECK: bb.2.else:
+; CHECK: ; predecessors: %bb.0
+; CHECK:   successors: %bb.3(0x80000000); %bb.3(100.00%)
+; CHECK:   liveins: $x10, $x11
+; CHECK:   renamable $x10 = SUB killed renamable $x10, killed renamable $x11
+; CHECK:
+; CHECK: bb.3.end:
+; CHECK: ; predecessors: %bb.2, %bb.1
+; CHECK:   liveins: $x10
+; CHECK:   PseudoRET implicit killed $x10
 
 define i64 @test_control_flow(i64 %a, i64 %b, i64 %cond) {
 entry:
@@ -48,7 +69,9 @@ end:
 ; CHECK: bb.0.entry:
 ; CHECK:   liveins: $x10
 ; CHECK: bb.1.loop:
+; CHECK-NOT: liveins:
 ; CHECK: bb.2.exit:
+; CHECK-NOT: liveins:
 
 define i64 @test_loop(i64 %n) {
 entry:

>From b72508d778775b11b1535b4c3d91b8e6ddea1cdf Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sat, 22 Nov 2025 18:28:07 -0800
Subject: [PATCH 18/32] Add tests for post-regalloc liveness analysis

---
 .../RISCV/live-variables-mbb-liveins.ll       | 107 +++++++++++++-----
 1 file changed, 80 insertions(+), 27 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll b/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll
index f553e75931e48..547ba6ee764d9 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll
+++ b/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll
@@ -1,8 +1,12 @@
+; Pre-regalloc test
 ; RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs \
 ; RUN: -riscv-liveness-update-kills -stop-after=riscv-live-variables \
 ; RUN: -riscv-liveness-update-mbb-liveins < %s | FileCheck %s
 
-; Test that updateMBBLiveIns correctly updates the live-in sets of basic blocks
+; Post-regalloc test
+; RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs \
+; RUN: -riscv-liveness-update-kills -stop-after=riscv-live-variables,1 \
+; RUN: -riscv-liveness-update-mbb-liveins < %s | FileCheck %s --check-prefix=CHECK-PR
 
 ; Basic test: simple function with two arguments
 ; CHECK-LABEL: name: test_mbb_liveins
@@ -21,30 +25,27 @@ entry:
 }
 
 ; Test with control flow: verify live-ins are correct for entry block with multiple args
-; CHECK-LABEL: name: test_control_flow
-; CHECK: bb.0.entry:
-; CHECK:   successors: %bb.1(0x30000000), %bb.2(0x50000000); %bb.1(37.50%), %bb.2(62.50%)
-; CHECK:   liveins: $x10, $x11, $x12
-; CHECK:   BNE killed renamable $x12, killed $x0, %bb.2
-; CHECK:   PseudoBR %bb.1
-; CHECK:
-; CHECK: bb.1.then:
-; CHECK: ; predecessors: %bb.0
-; CHECK:   successors: %bb.3(0x80000000); %bb.3(100.00%)
-; CHECK:   liveins: $x10, $x11
-; CHECK:   renamable $x10 = ADD killed renamable $x10, killed renamable $x11
-; CHECK:   PseudoBR %bb.3
-; CHECK:
-; CHECK: bb.2.else:
-; CHECK: ; predecessors: %bb.0
-; CHECK:   successors: %bb.3(0x80000000); %bb.3(100.00%)
-; CHECK:   liveins: $x10, $x11
-; CHECK:   renamable $x10 = SUB killed renamable $x10, killed renamable $x11
-; CHECK:
-; CHECK: bb.3.end:
-; CHECK: ; predecessors: %bb.2, %bb.1
-; CHECK:   liveins: $x10
-; CHECK:   PseudoRET implicit killed $x10
+; CHECK-PR-LABEL: name{{.*}}test_control_flow
+; CHECK-PR: bb.0.entry:
+; CHECK-PR:   successors:
+; CHECK-PR:   liveins: $x10, $x11, $x12
+; CHECK-PR:   BNE killed renamable $x12, killed $x0, %bb.2
+; CHECK-PR:   PseudoBR %bb.1
+
+; CHECK-PR: bb.1.then:
+; CHECK-PR:   successors:
+; CHECK-PR:   liveins: $x10, $x11
+; CHECK-PR:   renamable $x10 = ADD killed renamable $x10, killed renamable $x11
+; CHECK-PR:   PseudoBR %bb.3
+
+; CHECK-PR: bb.2.else:
+; CHECK-PR:   successors:
+; CHECK-PR:   liveins: $x10, $x11
+; CHECK-PR:   renamable $x10 = SUB killed renamable $x10, killed renamable $x11
+
+; CHECK-PR: bb.3.end:
+; CHECK-PR:   liveins: $x10
+; CHECK-PR:   PseudoRET implicit killed $x10
 
 define i64 @test_control_flow(i64 %a, i64 %b, i64 %cond) {
 entry:
@@ -353,6 +354,60 @@ exit:
 ; CHECK-LABEL: name: test_loop_multiple_exits
 ; CHECK: bb.0.entry:
 ; CHECK:   liveins: $x10, $x11, $x12
+; CHECK:   %10:gpr = COPY killed %11
+
+; CHECK: bb.3.loop_continue:
+; CHECK:   %4:gpr = ADD killed %3, %9
+; CHECK:   %5:gpr = ADDI killed %2, 1
+; CHECK:   %6:gpr = ADD killed %1, %0
+; CHECK:   PseudoBR %bb.1
+
+; CHECK: bb.4.exit1:
+; CHECK:   $x10 = COPY killed %3
+; CHECK:   PseudoRET implicit $x10
+
+; CHECK: bb.5.exit2:
+; CHECK:   $x10 = COPY killed %1
+; CHECK:   PseudoRET implicit $x10
+
+; CHECK-PR-LABEL: test_loop_multiple_exits
+; CHECK-PR:  bb.0.entry:
+; CHECK-PR:    successors:
+; CHECK-PR:    liveins: $x10, $x11, $x12
+; CHECK-PR:    renamable $x13 = COPY killed $x10
+; CHECK-PR:    renamable $x10 = COPY $x0
+; CHECK-PR:    renamable $x15 = COPY $x0
+; CHECK-PR:    renamable $x14 = COPY killed $x0
+; CHECK-PR:    renamable $x16 = SLLI renamable $x12, 1
+
+; CHECK-PR:  bb.1.loop:
+; CHECK-PR:    successors:
+; CHECK-PR:    liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16
+; CHECK-PR:    BLTU renamable $x11, renamable $x14, %bb.4
+; CHECK-PR:    PseudoBR %bb.2
+
+; CHECK-PR:  bb.2.check2:
+; CHECK-PR:    successors:
+; CHECK-PR:    liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16
+; CHECK-PR:    BLTU renamable $x13, renamable $x15, %bb.5
+; CHECK-PR:    PseudoBR %bb.3
+
+; CHECK-PR:  bb.3.loop_continue:
+; CHECK-PR:    successors:
+; CHECK-PR:    liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16
+; CHECK-PR:    renamable $x14 = ADD killed renamable $x14, renamable $x12
+; CHECK-PR:    renamable $x15 = ADDI killed renamable $x15, 1
+; CHECK-PR:    renamable $x10 = ADD killed renamable $x10, renamable $x16
+; CHECK-PR:    PseudoBR %bb.1
+
+; CHECK-PR:  bb.4.exit1:
+; CHECK-PR:    liveins: $x14
+; CHECK-PR:    $x10 = COPY killed renamable $x14
+; CHECK-PR:    PseudoRET implicit killed $x10
+
+; CHECK-PR:  bb.5.exit2:
+; CHECK-PR:    liveins: $x10
+; CHECK-PR:    PseudoRET implicit killed $x10
 
 define i64 @test_loop_multiple_exits(i64 %n, i64 %threshold, i64 %increment) {
 entry:
@@ -362,12 +417,10 @@ loop:
   %i = phi i64 [ 0, %entry ], [ %i_next, %loop_continue ]
   %sum = phi i64 [ 0, %entry ], [ %sum_next, %loop_continue ]
 
-  ; Check for exit condition 1
   %cmp1 = icmp ugt i64 %sum, %threshold
   br i1 %cmp1, label %exit1, label %check2
 
 check2:
-  ; Check for exit condition 2
   %cmp2 = icmp ugt i64 %i, %n
   br i1 %cmp2, label %exit2, label %loop_continue
 

>From d0a63a837b2da3856faf73143e76711ad69d9573 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Thu, 4 Dec 2025 11:01:33 -0800
Subject: [PATCH 19/32] Update default flags

---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index 2af52b9c573f0..c0451270a7785 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -45,20 +45,20 @@ STATISTIC(NumLiveRegsAtEntry, "Number of registers live at function entry");
 STATISTIC(NumLiveRegsTotal, "Total number of live registers across all blocks");
 
 static cl::opt<bool> UpdateKills("riscv-liveness-update-kills",
-                                 cl::desc("Update kill flags"), cl::init(false),
+                                 cl::desc("Update kill flags"), cl::init(true),
                                  cl::Hidden);
 
 static cl::opt<bool> UpdateLiveIns("riscv-liveness-update-mbb-liveins",
                                    cl::desc("Update MBB live-in sets"),
-                                   cl::init(false), cl::Hidden);
+                                   cl::init(true), cl::Hidden);
 
 static cl::opt<unsigned> MaxVRegs("riscv-liveness-max-vregs",
                                   cl::desc("Maximum VRegs to track"),
                                   cl::init(1024), cl::Hidden);
 
-static cl::opt<unsigned> VerifyLiveness("riscv-liveness-verify",
+static cl::opt<bool> VerifyLiveness("riscv-liveness-verify",
                                         cl::desc("Verify liveness information"),
-                                        cl::init(true), cl::Hidden);
+                                        cl::init(false), cl::Hidden);
 
 namespace {
 

>From e90f952163ceaa647ab25058288f1670029f2ff1 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Thu, 4 Dec 2025 11:18:56 -0800
Subject: [PATCH 20/32] Use TargetTriple to bail out for RV32

---
 llvm/lib/Target/RISCV/RISCV.h                |  3 ++-
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp | 19 +++++++++++--------
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp | 13 +++++++------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h
index 558d7d1987570..78c55407adca2 100644
--- a/llvm/lib/Target/RISCV/RISCV.h
+++ b/llvm/lib/Target/RISCV/RISCV.h
@@ -108,7 +108,8 @@ void initializeRISCVPreAllocZilsdOptPass(PassRegistry &);
 FunctionPass *createRISCVZacasABIFixPass();
 void initializeRISCVZacasABIFixPass(PassRegistry &);
 
-FunctionPass *createRISCVLiveVariablesPass(bool PreRegAlloc);
+FunctionPass *createRISCVLiveVariablesPass(RISCVTargetMachine &TM,
+                                           bool PreRegAlloc);
 void initializeRISCVLiveVariablesPass(PassRegistry &);
 
 InstructionSelector *
diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index c0451270a7785..9daaead31afac 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -19,6 +19,7 @@
 #include "RISCV.h"
 #include "RISCVInstrInfo.h"
 #include "RISCVSubtarget.h"
+#include "RISCVTargetMachine.h"
 #include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/PostOrderIterator.h"
@@ -57,8 +58,8 @@ static cl::opt<unsigned> MaxVRegs("riscv-liveness-max-vregs",
                                   cl::init(1024), cl::Hidden);
 
 static cl::opt<bool> VerifyLiveness("riscv-liveness-verify",
-                                        cl::desc("Verify liveness information"),
-                                        cl::init(false), cl::Hidden);
+                                    cl::desc("Verify liveness information"),
+                                    cl::init(false), cl::Hidden);
 
 namespace {
 
@@ -84,8 +85,8 @@ class RISCVLiveVariables : public MachineFunctionPass {
 public:
   static char ID;
 
-  RISCVLiveVariables(bool PreRegAlloc)
-      : MachineFunctionPass(ID), PreRegAlloc(PreRegAlloc) {
+  RISCVLiveVariables(RISCVTargetMachine &TM, bool PreRegAlloc)
+      : MachineFunctionPass(ID), TM(TM), PreRegAlloc(PreRegAlloc) {
     initializeRISCVLiveVariablesPass(*PassRegistry::getPassRegistry());
   }
 
@@ -143,6 +144,7 @@ class RISCVLiveVariables : public MachineFunctionPass {
   bool isTrackableRegister(Register Reg, const TargetRegisterInfo *TRI,
                            const MachineRegisterInfo *MRI) const;
 
+  RISCVTargetMachine &TM;
   bool PreRegAlloc;
   unsigned RegCounter = 0;
 
@@ -167,8 +169,9 @@ char RISCVLiveVariables::ID = 0;
 INITIALIZE_PASS(RISCVLiveVariables, DEBUG_TYPE, RISCV_LIVE_VARIABLES_NAME,
                 false, true)
 
-FunctionPass *llvm::createRISCVLiveVariablesPass(bool PreRegAlloc) {
-  return new RISCVLiveVariables(PreRegAlloc);
+FunctionPass *llvm::createRISCVLiveVariablesPass(RISCVTargetMachine &TM,
+                                                 bool PreRegAlloc) {
+  return new RISCVLiveVariables(TM, PreRegAlloc);
 }
 
 bool RISCVLiveVariables::isTrackableRegister(
@@ -519,8 +522,8 @@ bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
   const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
 
   // Verify we're targeting RV64
-  if (!Subtarget.is64Bit()) {
-    LLVM_DEBUG(dbgs() << "Warning: RISCVLiveVariables optimized for RV64, "
+  if (!TM.getTargetTriple().isRISCV64()) {
+    LLVM_DEBUG(dbgs() << "Warning: RISCVLiveVariables only intended for RV64, "
                       << "but running on RV32\n");
     return false;
   }
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 4db4d3010d730..38dcb31d4c4eb 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -623,7 +623,7 @@ void RISCVPassConfig::addMachineSSAOptimization() {
   addPass(createRISCVVectorPeepholePass());
   addPass(createRISCVFoldMemOffsetPass());
   if (EnableRISCVLiveVariables)
-    addPass(createRISCVLiveVariablesPass(true));
+    addPass(createRISCVLiveVariablesPass(getRISCVTargetMachine(), true));
 
   TargetPassConfig::addMachineSSAOptimization();
 
@@ -657,12 +657,13 @@ void RISCVPassConfig::addFastRegAlloc() {
 
 
 void RISCVPassConfig::addPostRegAlloc() {
-  if (TM->getOptLevel() != CodeGenOptLevel::None &&
-      EnableRedundantCopyElimination)
-    addPass(createRISCVRedundantCopyEliminationPass());
+  if (TM->getOptLevel() != CodeGenOptLevel::None) {
+    if (EnableRedundantCopyElimination)
+      addPass(createRISCVRedundantCopyEliminationPass());
 
-  if (EnableRISCVLiveVariables)
-    addPass(createRISCVLiveVariablesPass(false));
+    if (EnableRISCVLiveVariables)
+      addPass(createRISCVLiveVariablesPass(getRISCVTargetMachine(), false));
+  }
 }
 
 bool RISCVPassConfig::addILPOpts() {

>From affcb2bfd98830a133195570005f159a031190ff Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sat, 6 Dec 2025 05:43:30 -0800
Subject: [PATCH 21/32] Add test from the bug report

---
 .../live-variables-mbb-liveness-crash.ll      | 41 +++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/live-variables-mbb-liveness-crash.ll

diff --git a/llvm/test/CodeGen/RISCV/live-variables-mbb-liveness-crash.ll b/llvm/test/CodeGen/RISCV/live-variables-mbb-liveness-crash.ll
new file mode 100644
index 0000000000000..85e016445b368
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/live-variables-mbb-liveness-crash.ll
@@ -0,0 +1,41 @@
+; RUN: llc -mtriple=riscv64 -mattr=+rva22u64 -riscv-enable-live-variables -stop-after=riscv-live-variables,1 < %s
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux-gnu"
+
+; CHECK:body:             |
+; CHECK:  bb.0.bb:
+; CHECK:    successors: %bb.1(0x00000000), %bb.2(0x80000000)
+; CHECK:    EH_LABEL <mcsymbol >
+; CHECK:    ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit killed $x2
+; CHECK:    $x10 = COPY $x0
+; CHECK:    $x11 = COPY $x0
+; CHECK:    $x12 = COPY $x0
+; CHECK:    PseudoCALL target-flags(riscv-call) @baz, csr_ilp32d_lp64d, implicit-def dead $x1, implicit killed $x10, implicit killed $x11, implicit killed $x12, implicit-def $x2
+; CHECK:    ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit killed $x2
+; CHECK:    EH_LABEL <mcsymbol >
+; CHECK:    PseudoBR %bb.1
+; CHECK:  bb.1.bb1:
+; CHECK:    successors:
+; CHECK:  bb.2.bb2 (landing-pad):
+; CHECK:    EH_LABEL <mcsymbol >
+; CHECK:    ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit killed $x2
+; CHECK:    $x10 = COPY killed $x0
+; CHECK:    PseudoCALL target-flags(riscv-call) @_Unwind_Resume, csr_ilp32d_lp64d, implicit-def dead $x1, implicit killed $x10, implicit-def $x2
+; CHECK:    ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit killed $x2
+
+define i1 @widget() personality ptr null {
+bb:
+  invoke void (ptr, ptr, ...) @baz(ptr null, ptr null, ptr null)
+          to label %bb1 unwind label %bb2
+
+bb1:                                              ; preds = %bb
+  unreachable
+
+bb2:                                              ; preds = %bb
+  %landingpad = landingpad { ptr, i32 }
+          cleanup
+  resume { ptr, i32 } zeroinitializer
+}
+
+declare void @baz(ptr, ptr, ...)
+

>From 1458fe8edbb6ee9080a102ac4691a52d8c6bbd18 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sat, 18 Apr 2026 07:11:24 -0700
Subject: [PATCH 22/32] Fix incorrect RegCounter increment

---
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp    | 17 ++++++++---------
 .../test/CodeGen/RISCV/live-variables-basic.mir |  2 +-
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
index 9daaead31afac..b52a02bd8b6f5 100644
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
@@ -35,7 +35,6 @@
 #include "llvm/Support/raw_ostream.h"
 
 #include <set>
-#include <unordered_map>
 
 using namespace llvm;
 
@@ -151,6 +150,7 @@ class RISCVLiveVariables : public MachineFunctionPass {
   // PreRA can have large number of registers and basic block
   // level liveness may be expensive without a bitvector representation.
   std::unordered_map<unsigned, unsigned> TrackedRegisters;
+  DenseMap<Register, unsigned> TrackedRegisters;
 
   /// Liveness information for each basic block
   DenseMap<const MachineBasicBlock *, LivenessInfo> BlockLiveness;
@@ -202,6 +202,9 @@ void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
     Register Reg = MO.getReg();
 
     TrackedRegisters.insert(std::pair(Reg, RegCounter++));
+    auto [It, Inserted] = TrackedRegisters.insert({Reg, RegCounter});
+    if (Inserted)
+      RegCounter++;
 
     // Skip non-trackable registers
     if (!isTrackableRegister(Reg, TRI, MRI))
@@ -212,25 +215,21 @@ void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
       if (Info.Gen.find(Reg) == Info.Gen.end()) {
         Info.Use.insert(Reg);
 
-        // Also handle sub-registers for physical registers
         if (Reg.isPhysical()) {
+          // Also handle sub-registers for physical registers
           for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
                SubRegs.isValid(); ++SubRegs) {
             if (Info.Gen.find(*SubRegs) == Info.Gen.end()) {
               Info.Use.insert(*SubRegs);
             }
           }
+          // Implicit operands (like condition codes, stack pointer updates)
+          if (MO.isImplicit())
+            Info.Use.insert(Reg); // no sub-registers added.
         }
       }
     }
 
-    // Handle implicit operands (like condition codes, stack pointer updates)
-    if (MO.isImplicit() && MO.isUse() && Reg.isPhysical()) {
-      if (Info.Gen.find(Reg) == Info.Gen.end()) {
-        Info.Use.insert(Reg);
-      }
-    }
-
     if (MO.isDef()) // Collect defs for later processing.
       GenVec.push_back(Reg);
   }
diff --git a/llvm/test/CodeGen/RISCV/live-variables-basic.mir b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
index bc3cee44b3878..aaf5bdec6708a 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-basic.mir
+++ b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
@@ -3,7 +3,7 @@
 #
 # Test basic live variable analysis with simple control flow and basic blocks
 
-# REQUIRES: Assertions
+# REQUIRES: asserts
 
 --- |
   define i64 @test_simple_add(i64 %a, i64 %b) {

>From 06436e87f5277f145b3c8760166360022591f7d9 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sat, 18 Apr 2026 14:07:01 -0700
Subject: [PATCH 23/32] Make pass target independent

---
 llvm/include/llvm/CodeGen/Passes.h            |    3 +
 .../llvm/CodeGen/SparseLiveVariables.h        |  119 ++
 llvm/include/llvm/InitializePasses.h          |    1 +
 llvm/lib/CodeGen/CMakeLists.txt               |    1 +
 llvm/lib/CodeGen/CodeGen.cpp                  |    1 +
 llvm/lib/CodeGen/SparseLiveVariables.cpp      |  148 +++
 llvm/lib/Target/RISCV/CMakeLists.txt          |    1 -
 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp  |  600 ----------
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp  |    5 +-
 .../CodeGen/RISCV/live-variables-basic.mir    |   61 +-
 .../RISCV/live-variables-edge-cases.ll        |  234 ++--
 .../CodeGen/RISCV/live-variables-loops.ll     |  197 ++--
 .../RISCV/live-variables-mbb-liveins.ll       | 1029 ++++++++++++++---
 .../live-variables-mbb-liveness-crash.ll      |   23 +-
 .../RISCV/live-variables-pre-regalloc.ll      |   88 +-
 .../test/CodeGen/RISCV/live-variables-rv64.ll |  144 +--
 llvm/unittests/CodeGen/CMakeLists.txt         |    1 +
 .../CodeGen/SparseLiveVariablesTest.cpp       |  100 ++
 18 files changed, 1703 insertions(+), 1053 deletions(-)
 create mode 100644 llvm/include/llvm/CodeGen/SparseLiveVariables.h
 create mode 100644 llvm/lib/CodeGen/SparseLiveVariables.cpp
 delete mode 100644 llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
 create mode 100644 llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp

diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h
index be344c6aaf40e..2111260755520 100644
--- a/llvm/include/llvm/CodeGen/Passes.h
+++ b/llvm/include/llvm/CodeGen/Passes.h
@@ -155,6 +155,9 @@ LLVM_ABI extern char &EdgeBundlesWrapperLegacyID;
 /// variable is life and sets machine operand kill flags.
 LLVM_ABI extern char &LiveVariablesID;
 
+  /// SparseLiveVariables - Sparse Live Variable Analysis.
+  extern char &SparseLiveVariablesID;
+
 /// PHIElimination - This pass eliminates machine instruction PHI nodes
 /// by inserting copy instructions.  This destroys SSA information, but is the
 /// desired input for some register allocators.  This pass is "required" by
diff --git a/llvm/include/llvm/CodeGen/SparseLiveVariables.h b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
new file mode 100644
index 0000000000000..e39a1b2089d0f
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
@@ -0,0 +1,119 @@
+//===-- SparseLiveVariables.h - RISC-V Live Variable Analysis ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_SPARSELIVEVARIABLES_H
+#define LLVM_CODEGEN_SPARSELIVEVARIABLES_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SparseBitVector.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
+
+namespace llvm {
+
+class SparseLiveVariables : public MachineFunctionPass {
+public:
+  static char ID;
+
+  SparseLiveVariables() : MachineFunctionPass(ID) {}
+
+  struct BlockInfo {
+    SparseBitVector<> LiveIn;
+    SparseBitVector<> LiveOut;
+  };
+
+  DenseMap<const MachineBasicBlock *, BlockInfo> BlockLiveness;
+
+  class LivenessTracker {
+    SparseBitVector<> LiveRegs;
+    const MachineRegisterInfo *MRI;
+
+  public:
+    bool isTrackableRegister(Register Reg) const {
+      if (Reg.isVirtual()) return true;
+      if (Reg.isPhysical()) {
+        if (MRI->isReserved(Reg)) return false;
+        return true;
+      }
+      return false;
+    }
+
+    LivenessTracker(const SparseBitVector<> &LiveOut,
+                    const MachineRegisterInfo *MRI)
+: LiveRegs(LiveOut), MRI(MRI) {}
+
+    void stepBackward(const MachineInstr &MI) {
+      if (MI.isDebugInstr() || MI.isMetaInstruction())
+        return;
+
+      for (const MachineOperand &MO : MI.operands()) {
+        if (MO.isReg() && MO.isDef()) {
+          Register Reg = MO.getReg();
+          if (Reg.isValid() && isTrackableRegister(Reg))
+            LiveRegs.reset(Reg.id());
+        }
+      }
+
+      if (!MI.isPHI()) {
+        for (const MachineOperand &MO : MI.operands()) {
+          if (MO.isReg() && MO.isUse()) {
+            Register Reg = MO.getReg();
+            if (Reg.isValid() && isTrackableRegister(Reg))
+              LiveRegs.set(Reg.id());
+          }
+        }
+      }
+    }
+
+    bool isLive(Register Reg) const {
+      if (!Reg.isValid()) return false;
+      return LiveRegs.test(Reg.id());
+    }
+
+    const SparseBitVector<> &getLiveSet() const { return LiveRegs; }
+  };
+
+
+  const SparseBitVector<> &getLiveInSet(const MachineBasicBlock *MBB) const {
+    auto It = BlockLiveness.find(MBB);
+    assert(It != BlockLiveness.end() && "Block not analyzed");
+    return It->second.LiveIn;
+  }
+
+  const SparseBitVector<> &getLiveOutSet(const MachineBasicBlock *MBB) const {
+    auto It = BlockLiveness.find(MBB);
+    assert(It != BlockLiveness.end() && "Block not analyzed");
+    return It->second.LiveOut;
+  }
+
+  bool isLiveAfter(Register Reg, const MachineInstr &MI) const;
+  bool isLiveAt(Register Reg, const MachineInstr &MI) const;
+  bool isKillAt(Register Reg, const MachineInstr &MI) const;
+  void verifyLiveness(const MachineFunction &MF) const;
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+
+  StringRef getPassName() const override { return "RISC-V Live Variable Analysis"; }
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesAll();
+    MachineFunctionPass::getAnalysisUsage(AU);
+  }
+
+private:
+  const MachineRegisterInfo *MRI;
+  const TargetRegisterInfo *TRI;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_CODEGEN_SPARSELIVEVARIABLES_H
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 012f1fb0ebd90..f5c5dfb49fa54 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -170,6 +170,7 @@ LLVM_ABI void initializeLiveRangeShrinkPass(PassRegistry &);
 LLVM_ABI void initializeLiveRegMatrixWrapperLegacyPass(PassRegistry &);
 LLVM_ABI void initializeLiveStacksWrapperLegacyPass(PassRegistry &);
 LLVM_ABI void initializeLiveVariablesWrapperPassPass(PassRegistry &);
+LLVM_ABI void initializeSparseLiveVariablesPass(PassRegistry &);
 LLVM_ABI void initializeLoadStoreOptPass(PassRegistry &);
 LLVM_ABI void initializeLoadStoreVectorizerLegacyPassPass(PassRegistry &);
 LLVM_ABI void initializeLocalStackSlotPassPass(PassRegistry &);
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index 1cdf81791dc72..02869a89da49f 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -102,6 +102,7 @@ add_llvm_component_library(LLVMCodeGen
   LiveRegUnits.cpp
   LiveStacks.cpp
   LiveVariables.cpp
+  SparseLiveVariables.cpp
   CodeGenTargetMachineImpl.cpp
   LocalStackSlotAllocation.cpp
   LoopTraversal.cpp
diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp
index bb8bbc4f44eed..3051d49b168fa 100644
--- a/llvm/lib/CodeGen/CodeGen.cpp
+++ b/llvm/lib/CodeGen/CodeGen.cpp
@@ -73,6 +73,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
   initializeLiveRangeShrinkPass(Registry);
   initializeLiveStacksWrapperLegacyPass(Registry);
   initializeLiveVariablesWrapperPassPass(Registry);
+  initializeSparseLiveVariablesPass(Registry);
   initializeLocalStackSlotPassPass(Registry);
   initializeLowerEmuTLSPass(Registry);
   initializeLowerGlobalDtorsLegacyPassPass(Registry);
diff --git a/llvm/lib/CodeGen/SparseLiveVariables.cpp b/llvm/lib/CodeGen/SparseLiveVariables.cpp
new file mode 100644
index 0000000000000..eb1d7fcc0741d
--- /dev/null
+++ b/llvm/lib/CodeGen/SparseLiveVariables.cpp
@@ -0,0 +1,148 @@
+#include "llvm/CodeGen/SparseLiveVariables.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/ADT/SparseBitVector.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "sparse-live-variables"
+
+char SparseLiveVariables::ID = 0;
+INITIALIZE_PASS(SparseLiveVariables, DEBUG_TYPE, "Sparse Live Variable Analysis", false, false)
+
+bool SparseLiveVariables::runOnMachineFunction(MachineFunction &MF) {
+  if (skipFunction(MF.getFunction()) || MF.empty())
+    return false;
+
+  MRI = &MF.getRegInfo();
+  TRI = MF.getSubtarget().getRegisterInfo();
+  
+  BlockLiveness.clear();
+
+  SmallPtrSet<MachineBasicBlock *, 16> Reachable;
+  for (MachineBasicBlock *MBB : llvm::depth_first(&MF))
+    Reachable.insert(MBB);
+
+  bool Changed = true;
+  while (Changed) {
+    Changed = false;
+    for (MachineBasicBlock *MBB : llvm::post_order(&MF)) {
+      if (!Reachable.count(MBB)) continue;
+
+      SparseBitVector<> OldLiveIn = BlockLiveness[MBB].LiveIn;
+      SparseBitVector<> OldLiveOut = BlockLiveness[MBB].LiveOut;
+
+      for (const MachineBasicBlock *Succ : MBB->successors())
+        if (Reachable.count(Succ))
+          BlockLiveness[MBB].LiveOut |= BlockLiveness[Succ].LiveIn;
+
+      SparseBitVector<> LiveIn = BlockLiveness[MBB].LiveOut;
+      LivenessTracker Tracker(LiveIn, MRI);
+
+      for (MachineInstr &MI : llvm::reverse(*MBB))
+        Tracker.stepBackward(MI);
+
+      BlockLiveness[MBB].LiveIn = Tracker.getLiveSet();
+
+      if (BlockLiveness[MBB].LiveIn != OldLiveIn ||
+          BlockLiveness[MBB].LiveOut != OldLiveOut)
+        Changed = true;
+    }
+  }
+
+  LLVM_DEBUG({
+    dbgs() << "--- API Testing for " << MF.getName() << " ---\n";
+    for (const MachineBasicBlock &MBB : MF) {
+      dbgs() << "MBB: " << printMBBReference(MBB) << "\n";
+      for (const MachineInstr &MI : MBB) {
+        dbgs() << "  " << MI;
+        for (const MachineOperand &MO : MI.operands()) {
+          if (MO.isReg() && MO.getReg().isValid() && MO.getReg().isVirtual()) {
+            Register Reg = MO.getReg();
+            dbgs() << "    Reg " << printReg(Reg, TRI) 
+                   << " isLiveAfter: " << isLiveAfter(Reg, MI)
+                   << ", isLiveAt: " << isLiveAt(Reg, MI)
+                   << ", isKillAt: " << isKillAt(Reg, MI) << "\n";
+          }
+        }
+      }
+    }
+  });
+
+  return false;
+}
+
+
+
+
+bool SparseLiveVariables::isLiveAfter(Register Reg, const MachineInstr &MI) const {
+  const MachineBasicBlock *MBB = MI.getParent();
+  auto It = BlockLiveness.find(MBB);
+  if (It == BlockLiveness.end()) return false;
+
+  LivenessTracker Tracker(It->second.LiveOut, MRI);
+  for (const MachineInstr &I : llvm::reverse(*MBB)) {
+    if (&I == &MI)
+      return Tracker.isLive(Reg);
+    Tracker.stepBackward(I);
+  }
+  return Tracker.isLive(Reg);
+}
+
+bool SparseLiveVariables::isLiveAt(Register Reg, const MachineInstr &MI) const {
+  const MachineBasicBlock *MBB = MI.getParent();
+  auto It = BlockLiveness.find(MBB);
+  if (It == BlockLiveness.end()) return false;
+
+  LivenessTracker Tracker(It->second.LiveOut, MRI);
+  for (const MachineInstr &I : llvm::reverse(*MBB)) {
+    Tracker.stepBackward(I);
+    if (&I == &MI)
+      return Tracker.isLive(Reg);
+  }
+  return Tracker.isLive(Reg);
+}
+
+bool SparseLiveVariables::isKillAt(Register Reg, const MachineInstr &MI) const {
+  const MachineBasicBlock *MBB = MI.getParent();
+  auto It = BlockLiveness.find(MBB);
+  if (It == BlockLiveness.end()) return false;
+
+  LivenessTracker Tracker(It->second.LiveOut, MRI);
+  for (const MachineInstr &I : llvm::reverse(*MBB)) {
+    bool LiveAfter = Tracker.isLive(Reg);
+    Tracker.stepBackward(I);
+    if (&I == &MI) {
+      bool LiveBefore = Tracker.isLive(Reg);
+      return !LiveAfter && LiveBefore && MI.readsRegister(Reg, TRI);
+    }
+  }
+
+  return false;
+}
+
+void SparseLiveVariables::verifyLiveness(const MachineFunction &MF) const {
+  for (const MachineBasicBlock &MBB : MF) {
+    auto It = BlockLiveness.find(&MBB);
+    if (It == BlockLiveness.end()) continue;
+
+    const SparseBitVector<> &LiveIn = It->second.LiveIn;
+    for (const auto &LI : MBB.liveins()) {
+      if (!LiveIn.test(LI.PhysReg.id())) {
+        LLVM_DEBUG(dbgs() << "Warning: Live-in register " << printReg(LI.PhysReg, TRI)
+                          << " missing from computed live-in set of block "
+                          << printMBBReference(MBB) << "\n");
+      }
+    }
+  }
+}
+char &llvm::SparseLiveVariablesID = SparseLiveVariables::ID;
diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index d94d40ebadcc3..3b529c1471d54 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -51,7 +51,6 @@ add_llvm_target(RISCVCodeGen
   RISCVISelLowering.cpp
   RISCVLandingPadSetup.cpp
   RISCVLateBranchOpt.cpp
-  RISCVLiveVariables.cpp
   RISCVLoadStoreOptimizer.cpp
   RISCVMachineFunctionInfo.cpp
   RISCVMakeCompressible.cpp
diff --git a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp b/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
deleted file mode 100644
index b52a02bd8b6f5..0000000000000
--- a/llvm/lib/Target/RISCV/RISCVLiveVariables.cpp
+++ /dev/null
@@ -1,600 +0,0 @@
-//===- RISCVLiveVariables.cpp - Live Variable Analysis for RISC-V --------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements a live variable analysis pass for the RISC-V backend.
-// The pass computes liveness information for virtual and physical registers
-// in RISC-V machine functions, optimized for RV64 (64-bit RISC-V architecture).
-//
-// The analysis performs a backward dataflow analysis to compute
-// liveness information. Also updates the kill flags on register operands.
-// There is also a verification step to ensure consistency with MBB live-ins.
-//
-//===----------------------------------------------------------------------===//
-
-#include "RISCV.h"
-#include "RISCVInstrInfo.h"
-#include "RISCVSubtarget.h"
-#include "RISCVTargetMachine.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/PostOrderIterator.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/CodeGen/MachineBasicBlock.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/CodeGen/MachineInstr.h"
-#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/TargetRegisterInfo.h"
-#include "llvm/InitializePasses.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <set>
-
-using namespace llvm;
-
-#define DEBUG_TYPE "riscv-live-variables"
-#define RISCV_LIVE_VARIABLES_NAME "RISC-V Live Variable Analysis"
-
-STATISTIC(NumLiveRegsAtEntry, "Number of registers live at function entry");
-STATISTIC(NumLiveRegsTotal, "Total number of live registers across all blocks");
-
-static cl::opt<bool> UpdateKills("riscv-liveness-update-kills",
-                                 cl::desc("Update kill flags"), cl::init(true),
-                                 cl::Hidden);
-
-static cl::opt<bool> UpdateLiveIns("riscv-liveness-update-mbb-liveins",
-                                   cl::desc("Update MBB live-in sets"),
-                                   cl::init(true), cl::Hidden);
-
-static cl::opt<unsigned> MaxVRegs("riscv-liveness-max-vregs",
-                                  cl::desc("Maximum VRegs to track"),
-                                  cl::init(1024), cl::Hidden);
-
-static cl::opt<bool> VerifyLiveness("riscv-liveness-verify",
-                                    cl::desc("Verify liveness information"),
-                                    cl::init(false), cl::Hidden);
-
-namespace {
-
-/// LivenessInfo - Stores liveness information for a basic block
-/// TODO: Optimize storage using BitVectors for large register sets.
-struct LivenessInfo {
-  /// Registers that are live into this block
-  /// LiveIn[B] = Use[B] U (LiveOut[B] - Def[B])
-  std::set<Register> LiveIn;
-
-  /// Registers that are live out of this block.
-  /// LiveOut[B] = U LiveIns[∀ Succ(B)].
-  std::set<Register> LiveOut;
-
-  /// Registers that are defined in this block
-  std::set<Register> Gen;
-
-  /// Registers that are used in this block before being defined (if at all).
-  std::set<Register> Use;
-};
-
-class RISCVLiveVariables : public MachineFunctionPass {
-public:
-  static char ID;
-
-  RISCVLiveVariables(RISCVTargetMachine &TM, bool PreRegAlloc)
-      : MachineFunctionPass(ID), TM(TM), PreRegAlloc(PreRegAlloc) {
-    initializeRISCVLiveVariablesPass(*PassRegistry::getPassRegistry());
-  }
-
-  bool runOnMachineFunction(MachineFunction &MF) override;
-
-  void getAnalysisUsage(AnalysisUsage &AU) const override {
-    MachineFunctionPass::getAnalysisUsage(AU);
-  }
-
-  StringRef getPassName() const override { return RISCV_LIVE_VARIABLES_NAME; }
-
-  /// Returns the set of registers live at the entry of the given basic block
-  const std::set<Register> &getLiveInSet(const MachineBasicBlock *MBB) const {
-    auto It = BlockLiveness.find(MBB);
-    assert(It != BlockLiveness.end() && "Block not analyzed");
-    return It->second.LiveIn;
-  }
-
-  /// Returns the set of registers live at the exit of the given basic block
-  const std::set<Register> &getLiveOutSet(const MachineBasicBlock *MBB) const {
-    auto It = BlockLiveness.find(MBB);
-    assert(It != BlockLiveness.end() && "Block not analyzed");
-    return It->second.LiveOut;
-  }
-
-  /// Check if a register is live at a specific instruction
-  bool isLiveAt(Register Reg, const MachineInstr &MI) const;
-
-  /// Print liveness information for debugging
-  void print(raw_ostream &OS, const Module *M = nullptr) const override;
-
-  /// Verify the computed liveness information against MBB live-ins.
-  /// TODO: Extend verification to live-outs and instruction-level liveness.
-  void verifyLiveness(MachineFunction &MF) const;
-
-  /// Mark operands that kill a register
-  /// TODO: Add and remove kill flags as necessary.
-  bool markKills(MachineFunction &MF);
-
-private:
-  /// Compute local liveness information (Use and Def sets) for each block
-  void computeLocalLiveness(MachineFunction &MF);
-
-  /// Compute global liveness information (LiveIn and LiveOut sets)
-  void computeGlobalLiveness(MachineFunction &MF);
-
-  /// Update MBB live-in sets based on computed liveness information
-  bool updateMBBLiveIns(MachineFunction &MF);
-
-  /// Process a single instruction to extract def/use information
-  void processInstruction(const MachineInstr &MI, LivenessInfo &Info,
-                          const TargetRegisterInfo *TRI);
-
-  /// Check if a register is allocatable (relevant for liveness tracking)
-  bool isTrackableRegister(Register Reg, const TargetRegisterInfo *TRI,
-                           const MachineRegisterInfo *MRI) const;
-
-  RISCVTargetMachine &TM;
-  bool PreRegAlloc;
-  unsigned RegCounter = 0;
-
-  // PreRA can have large number of registers and basic block
-  // level liveness may be expensive without a bitvector representation.
-  std::unordered_map<unsigned, unsigned> TrackedRegisters;
-  DenseMap<Register, unsigned> TrackedRegisters;
-
-  /// Liveness information for each basic block
-  DenseMap<const MachineBasicBlock *, LivenessInfo> BlockLiveness;
-
-  /// Cached pointer to MachineRegisterInfo
-  const MachineRegisterInfo *MRI;
-
-  /// Cached pointer to TargetRegisterInfo
-  const TargetRegisterInfo *TRI;
-};
-
-} // end anonymous namespace
-
-char RISCVLiveVariables::ID = 0;
-
-INITIALIZE_PASS(RISCVLiveVariables, DEBUG_TYPE, RISCV_LIVE_VARIABLES_NAME,
-                false, true)
-
-FunctionPass *llvm::createRISCVLiveVariablesPass(RISCVTargetMachine &TM,
-                                                 bool PreRegAlloc) {
-  return new RISCVLiveVariables(TM, PreRegAlloc);
-}
-
-bool RISCVLiveVariables::isTrackableRegister(
-    Register Reg, const TargetRegisterInfo *TRI,
-    const MachineRegisterInfo *MRI) const {
-  // Track all virtual registers but only allocatable physical registers.
-  // 1. General purpose registers (X0-X31)
-  // 2. Floating point registers (F0-F31)
-  // 3. Vector registers if present
-
-  if (Reg.isVirtual())
-    return true;
-
-  if (Reg.isPhysical())
-    return TRI->isInAllocatableClass(Reg);
-
-  return false;
-}
-
-void RISCVLiveVariables::processInstruction(const MachineInstr &MI,
-                                            LivenessInfo &Info,
-                                            const TargetRegisterInfo *TRI) {
-  std::vector<Register> GenVec;
-  for (const MachineOperand &MO : MI.operands()) {
-    if (!MO.isReg() || !MO.getReg())
-      continue;
-
-    Register Reg = MO.getReg();
-
-    TrackedRegisters.insert(std::pair(Reg, RegCounter++));
-    auto [It, Inserted] = TrackedRegisters.insert({Reg, RegCounter});
-    if (Inserted)
-      RegCounter++;
-
-    // Skip non-trackable registers
-    if (!isTrackableRegister(Reg, TRI, MRI))
-      continue;
-
-    if (MO.isUse()) {
-      // Only add to Use set if not already defined in this block.
-      if (Info.Gen.find(Reg) == Info.Gen.end()) {
-        Info.Use.insert(Reg);
-
-        if (Reg.isPhysical()) {
-          // Also handle sub-registers for physical registers
-          for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
-               SubRegs.isValid(); ++SubRegs) {
-            if (Info.Gen.find(*SubRegs) == Info.Gen.end()) {
-              Info.Use.insert(*SubRegs);
-            }
-          }
-          // Implicit operands (like condition codes, stack pointer updates)
-          if (MO.isImplicit())
-            Info.Use.insert(Reg); // no sub-registers added.
-        }
-      }
-    }
-
-    if (MO.isDef()) // Collect defs for later processing.
-      GenVec.push_back(Reg);
-  }
-
-  for (auto Reg : GenVec) {
-    Info.Gen.insert(Reg);
-    if (Reg.isPhysical()) {
-      for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
-           SubRegs.isValid(); ++SubRegs) {
-        Info.Gen.insert(*SubRegs);
-      }
-    }
-  }
-
-  // Handle RegMasks (from calls) - they kill all non-preserved registers
-  for (const MachineOperand &MO : MI.operands()) {
-    if (MO.isRegMask()) {
-      const uint32_t *RegMask = MO.getRegMask();
-
-      // Iterate through all physical registers
-      for (unsigned PhysReg = 1; PhysReg < TRI->getNumRegs(); ++PhysReg) {
-        // If the register is not preserved by this mask, it's clobbered
-        if (!MachineOperand::clobbersPhysReg(RegMask, PhysReg))
-          continue;
-
-        // Mark as defined (clobbered)
-        if (isTrackableRegister(Register(PhysReg), TRI, MRI)) {
-          Info.Gen.insert(Register(PhysReg));
-        }
-      }
-    }
-  }
-}
-
-void RISCVLiveVariables::computeLocalLiveness(MachineFunction &MF) {
-  LLVM_DEBUG(dbgs() << "Computing local liveness for " << MF.getName() << "\n");
-
-  // Process each basic block
-  for (MachineBasicBlock &MBB : MF) {
-    LivenessInfo &Info = BlockLiveness[&MBB];
-    Info.Gen.clear();
-    Info.Use.clear();
-
-    // Process instructions in forward order to build Use and Def sets
-    for (const MachineInstr &MI : MBB) {
-      // Skip debug instructions and meta instructions
-      if (MI.isDebugInstr() || MI.isMetaInstruction())
-        continue;
-
-      processInstruction(MI, Info, TRI);
-    }
-
-    LLVM_DEBUG({
-      dbgs() << "Block " << MBB.getName() << ":\n";
-      dbgs() << "  Use: ";
-      for (Register Reg : Info.Use)
-        dbgs() << printReg(Reg, TRI) << " ";
-      dbgs() << "\n  Def: ";
-      for (Register Reg : Info.Gen)
-        dbgs() << printReg(Reg, TRI) << " ";
-      dbgs() << "\n";
-    });
-  }
-}
-
-void RISCVLiveVariables::computeGlobalLiveness(MachineFunction &MF) {
-  LLVM_DEBUG(dbgs() << "Computing global liveness (fixed-point iteration)\n");
-
-  bool Changed = true;
-  [[maybe_unused]] unsigned Iterations = 0;
-
-  // Iterate until we reach a fixed point
-  // Live-out[B] = Union of Live-in[S] for all successors S of B
-  // Live-in[B] = Use[B] Union (Live-out[B] - Def[B])
-  while (Changed) {
-    Changed = false;
-    ++Iterations;
-
-    for (MachineBasicBlock *MBB : post_order(&MF)) {
-      LivenessInfo &Info = BlockLiveness[MBB];
-      std::set<Register> OldLiveIn = Info.LiveIn;
-      std::set<Register> NewLiveOut;
-
-      // Compute Live-out: Union of Live-in of all successors
-      for (MachineBasicBlock *Succ : MBB->successors()) {
-        LivenessInfo &SuccInfo = BlockLiveness[Succ];
-        NewLiveOut.insert(SuccInfo.LiveIn.begin(), SuccInfo.LiveIn.end());
-      }
-
-      Info.LiveOut = NewLiveOut;
-
-      // Compute Live-in: Use Union (Live-out - Def)
-      std::set<Register> NewLiveIn = Info.Use;
-
-      for (Register Reg : Info.LiveOut) {
-        if (Info.Gen.find(Reg) == Info.Gen.end()) {
-          NewLiveIn.insert(Reg);
-        }
-      }
-
-      Info.LiveIn = NewLiveIn;
-
-      // Check if anything changed
-      if (Info.LiveIn != OldLiveIn) {
-        Changed = true;
-      }
-    }
-  }
-
-  LLVM_DEBUG(dbgs() << "Global liveness converged in " << Iterations
-                    << " iterations\n");
-
-  // Update statistics
-  for (auto &Entry : BlockLiveness) {
-    NumLiveRegsTotal += Entry.second.LiveIn.size();
-  }
-
-  // Count live registers at function entry
-  if (!MF.empty()) {
-    const MachineBasicBlock &EntryBB = MF.front();
-    NumLiveRegsAtEntry += BlockLiveness[&EntryBB].LiveIn.size();
-  }
-}
-
-bool RISCVLiveVariables::updateMBBLiveIns(MachineFunction &MF) {
-  // Update each MBB's live-in set based on computed liveness
-  // Only update physical register live-ins, as MBB live-in sets
-  // track physical registers entering a block
-  bool Changed = false;
-  for (MachineBasicBlock &MBB : MF) {
-    auto It = BlockLiveness.find(&MBB);
-    if (It == BlockLiveness.end())
-      continue;
-
-    const LivenessInfo &Info = It->second;
-    Changed = true;
-
-    // Clear existing live-ins
-    MBB.clearLiveIns();
-
-    // Add computed live-in physical registers to the MBB
-    // Skip sub-registers - only add top-level registers
-    // Also skip reserved registers (stack pointer, zero register, etc.)
-    for (Register Reg : Info.LiveIn) {
-      if (Reg.isPhysical()) {
-        MCRegister MCReg = Reg.asMCReg();
-
-        // Skip reserved registers - they're implicitly always live
-        if (MRI->isReserved(Reg))
-          continue;
-
-        // Only add if this is not a sub-register of another register
-        // We want top-level registers only (e.g., $x10, not $x10_w)
-        bool IsSubReg = false;
-        for (MCSuperRegIterator SR(MCReg, TRI, /*IncludeSelf=*/false);
-             SR.isValid(); ++SR) {
-          if (Info.LiveIn.count(Register(*SR))) {
-            IsSubReg = true;
-            break;
-          }
-        }
-
-        if (!IsSubReg) {
-          MBB.addLiveIn(MCReg);
-          LLVM_DEBUG(dbgs() << "  Adding live-in " << printReg(Reg, TRI)
-                            << " to block " << MBB.getName() << "\n");
-        }
-      }
-    }
-
-    // Sort and unique the live-ins for efficient lookup
-    MBB.sortUniqueLiveIns();
-  }
-  return Changed;
-}
-
-bool RISCVLiveVariables::isLiveAt(Register Reg, const MachineInstr &MI) const {
-  const MachineBasicBlock *MBB = MI.getParent();
-  auto It = BlockLiveness.find(MBB);
-
-  if (It == BlockLiveness.end())
-    return false;
-
-  const LivenessInfo &Info = It->second;
-
-  // A register is live at an instruction if:
-  // 1. It's in the live-in set of the block, OR
-  // 2. It's defined before this instruction and used after (not yet killed)
-
-  // Check if it's live-in to the block
-  if (Info.LiveIn.count(Reg))
-    return true;
-
-  // For a more precise answer, we'd need to track instruction-level liveness
-  // For now, conservatively return true if it's in live-out and not killed yet
-  if (Info.LiveOut.count(Reg))
-    return true;
-
-  return false;
-}
-
-void RISCVLiveVariables::verifyLiveness(MachineFunction &MF) const {
-  for (auto &BB : MF) {
-    auto BBLiveness = BlockLiveness.find(&BB);
-    assert(BBLiveness != BlockLiveness.end() && "Missing Liveness");
-    auto &ComputedLivein = BBLiveness->second.LiveIn;
-    for (auto &LI : BB.getLiveIns()) {
-      if (!ComputedLivein.count(LI.PhysReg)) {
-        LLVM_DEBUG(dbgs() << "Warning: Live-in register "
-                          << printReg(LI.PhysReg, TRI)
-                          << " missing from computed live-in set of block "
-                          << BB.getName() << "\n");
-        llvm_unreachable("Computed live-in set is inconsistent with MBB.");
-      }
-    }
-  }
-}
-
-bool RISCVLiveVariables::markKills(MachineFunction &MF) {
-  bool Changed = false;
-  auto KillSetSize = PreRegAlloc ? RegCounter : TRI->getNumRegs();
-  for (MachineBasicBlock *MBB : post_order(&MF)) {
-    // Set all the registers that are not live-out of the block.
-    // Since the global liveness is available (even though a bit conservative),
-    // this initialization is safe.
-    llvm::BitVector KillSet(KillSetSize, true);
-    LivenessInfo &Info = BlockLiveness[MBB];
-
-    for (Register Reg : Info.LiveOut) {
-      auto RegIdx = PreRegAlloc ? TrackedRegisters[Reg] : Reg.asMCReg().id();
-      KillSet.reset(RegIdx);
-    }
-
-    for (MachineInstr &MI : reverse(*MBB)) {
-      for (MachineOperand &MO : MI.all_defs()) {
-        Register Reg = MO.getReg();
-        // Does not track physical registers pre-regalloc.
-        if ((PreRegAlloc && Reg.isPhysical()) ||
-            !isTrackableRegister(Reg, TRI, MRI))
-          continue;
-
-        assert(TrackedRegisters.find(Reg) != TrackedRegisters.end() &&
-               "Register not tracked");
-        auto RegIdx = PreRegAlloc ? TrackedRegisters[Reg] : Reg.asMCReg().id();
-
-        KillSet.set(RegIdx);
-
-        // Also handle sub-registers for physical registers
-        if (!PreRegAlloc && Reg.isPhysical()) {
-          for (MCRegAliasIterator RA(Reg, TRI, true); RA.isValid(); ++RA)
-            KillSet.set(*RA);
-        }
-      }
-
-      for (MachineOperand &MO : MI.all_uses()) {
-        Register Reg = MO.getReg();
-        // Does not track physical registers pre-regalloc.
-        if ((PreRegAlloc && Reg.isPhysical()) ||
-            !isTrackableRegister(Reg, TRI, MRI))
-          continue;
-
-        assert(TrackedRegisters.find(Reg) != TrackedRegisters.end() &&
-               "Register not tracked");
-        auto RegIdx = PreRegAlloc ? TrackedRegisters[Reg] : Reg.asMCReg().id();
-
-        if (KillSet[RegIdx]) {
-          if (!MO.isKill() && !MI.isPHI()) {
-            MO.setIsKill(true);
-            Changed = true;
-          }
-          LLVM_DEBUG(dbgs() << "Marking kill of " << printReg(Reg, TRI)
-                            << " at instruction: " << MI);
-          KillSet.reset(RegIdx);
-          if (Reg.isPhysical()) {
-            for (MCRegAliasIterator RA(Reg, TRI, true); RA.isValid(); ++RA)
-              KillSet.reset(*RA);
-          }
-        }
-      }
-    }
-  }
-  return Changed;
-}
-
-bool RISCVLiveVariables::runOnMachineFunction(MachineFunction &MF) {
-  if (skipFunction(MF.getFunction()) || MF.empty())
-    return false;
-
-  const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
-
-  // Verify we're targeting RV64
-  if (!TM.getTargetTriple().isRISCV64()) {
-    LLVM_DEBUG(dbgs() << "Warning: RISCVLiveVariables only intended for RV64, "
-                      << "but running on RV32\n");
-    return false;
-  }
-
-  MRI = &MF.getRegInfo();
-  TRI = Subtarget.getRegisterInfo();
-
-  LLVM_DEBUG(dbgs() << "***** RISC-V Live Variable Analysis *****\n");
-  LLVM_DEBUG(dbgs() << "Function: " << MF.getName() << "\n");
-
-  // Clear any previous analysis
-  BlockLiveness.clear();
-
-  // Step 1: Compute local liveness (Use and Def sets)
-  computeLocalLiveness(MF);
-
-  // Step 2: Compute global liveness (LiveIn and LiveOut sets)
-  computeGlobalLiveness(MF);
-
-  bool Changed = false;
-  // Step 3: Update live-in sets of MBBs based on computed liveness
-  if (UpdateLiveIns)
-    Changed = updateMBBLiveIns(MF);
-
-  // Step 4: Mark kill flags on operands
-  if (UpdateKills && MaxVRegs >= RegCounter)
-    Changed |= markKills(MF);
-
-  LLVM_DEBUG({
-    dbgs() << "\n***** Final Liveness Information *****\n";
-    print(dbgs());
-  });
-
-  if (VerifyLiveness)
-    verifyLiveness(MF);
-
-  return Changed;
-}
-
-void RISCVLiveVariables::print(raw_ostream &OS, const Module *M) const {
-  OS << "RISC-V Live Variable Analysis Results:\n";
-  OS << "======================================\n\n";
-
-  for (const auto &Entry : BlockLiveness) {
-    const MachineBasicBlock *MBB = Entry.first;
-    const LivenessInfo &Info = Entry.second;
-
-    OS << "Block: " << MBB->getName() << " (Number: " << MBB->getNumber()
-       << ")\n";
-
-    OS << "  Live-In:  { ";
-    for (Register Reg : Info.LiveIn) {
-      OS << printReg(Reg, TRI) << " ";
-    }
-    OS << "}\n";
-
-    OS << "  Live-Out: { ";
-    for (Register Reg : Info.LiveOut) {
-      OS << printReg(Reg, TRI) << " ";
-    }
-    OS << "}\n";
-
-    OS << "  Use:      { ";
-    for (Register Reg : Info.Use) {
-      OS << printReg(Reg, TRI) << " ";
-    }
-    OS << "}\n";
-
-    OS << "  Def:      { ";
-    for (Register Reg : Info.Gen) {
-      OS << printReg(Reg, TRI) << " ";
-    }
-    OS << "}\n\n";
-  }
-}
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 38dcb31d4c4eb..615692a3d0b8f 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -131,7 +131,6 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
   initializeRISCVPostLegalizerCombinerPass(*PR);
   initializeKCFIPass(*PR);
   initializeRISCVDeadRegisterDefinitionsPass(*PR);
-  initializeRISCVLiveVariablesPass(*PR);
   initializeRISCVLateBranchOptPass(*PR);
   initializeRISCVMakeCompressibleOptPass(*PR);
   initializeRISCVGatherScatterLoweringPass(*PR);
@@ -623,7 +622,7 @@ void RISCVPassConfig::addMachineSSAOptimization() {
   addPass(createRISCVVectorPeepholePass());
   addPass(createRISCVFoldMemOffsetPass());
   if (EnableRISCVLiveVariables)
-    addPass(createRISCVLiveVariablesPass(getRISCVTargetMachine(), true));
+    addPass(&SparseLiveVariablesID);
 
   TargetPassConfig::addMachineSSAOptimization();
 
@@ -662,7 +661,7 @@ void RISCVPassConfig::addPostRegAlloc() {
       addPass(createRISCVRedundantCopyEliminationPass());
 
     if (EnableRISCVLiveVariables)
-      addPass(createRISCVLiveVariablesPass(getRISCVTargetMachine(), false));
+      addPass(&SparseLiveVariablesID);
   }
 }
 
diff --git a/llvm/test/CodeGen/RISCV/live-variables-basic.mir b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
index aaf5bdec6708a..f8353e10c27b1 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-basic.mir
+++ b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
@@ -1,5 +1,5 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs -o - %s | FileCheck %s
+# RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs -run-pass=sparse-live-variables -o - %s | FileCheck %s
 #
 # Test basic live variable analysis with simple control flow and basic blocks
 
@@ -63,11 +63,16 @@ liveins:
 body:             |
   bb.0.entry:
     liveins: $x10, $x11
-    ; CHECK-LABEL: name: test_simple_add
-    ; CHECK: bb.0.entry:
-    ; CHECK-NEXT: liveins: $x10, $x11
     ; Test that %0 and %1 are live-in, used once, and %2 is defined
 
+    ; CHECK-LABEL: name: test_simple_add
+    ; CHECK: liveins: $x10, $x11
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+    ; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[COPY]], [[COPY1]]
+    ; CHECK-NEXT: $x10 = COPY [[ADD]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
     %0:gpr = COPY $x10
     %1:gpr = COPY $x11
     %2:gpr = ADD %0, %1
@@ -88,12 +93,34 @@ liveins:
   - { reg: '$x10', virtual-reg: '%0' }
   - { reg: '$x11', virtual-reg: '%1' }
 body:             |
+  ; CHECK-LABEL: name: test_if_then_else
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.1(0x40000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[SLT:%[0-9]+]]:gpr = SLT [[COPY1]], [[COPY]]
+  ; CHECK-NEXT:   BEQ [[SLT]], $x0, %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.then:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[MUL:%[0-9]+]]:gpr = MUL [[COPY]], [[COPY1]]
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.else:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SUB:%[0-9]+]]:gpr = SUB [[COPY]], [[COPY1]]
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.end:
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[MUL]], %bb.1, [[SUB]], %bb.2
+  ; CHECK-NEXT:   $x10 = COPY [[PHI]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
   bb.0.entry:
     liveins: $x10, $x11
-    ; CHECK-LABEL: name: test_if_then_else
-    ; CHECK: bb.0.entry:
-    ; CHECK-NEXT: successors
-    ; CHECK-NEXT: liveins: $x10, $x11
     ; Test that %0 and %1 are live across multiple blocks
 
     %0:gpr = COPY $x10
@@ -102,19 +129,16 @@ body:             |
     BEQ %2, $x0, %bb.2
 
   bb.1.then:
-    ; CHECK: bb.1.then:
     ; %0 and %1 should be live-in here
     %3:gpr = MUL %0, %1
     PseudoBR %bb.3
 
   bb.2.else:
-    ; CHECK: bb.2.else:
     ; %0 and %1 should be live-in here
     %4:gpr = SUB %0, %1
     PseudoBR %bb.3
 
   bb.3.end:
-    ; CHECK: bb.3.end:
     ; Either %3 or %4 should be live-in (phi sources)
     %5:gpr = PHI %3, %bb.1, %4, %bb.2
     $x10 = COPY %5
@@ -139,11 +163,20 @@ liveins:
 body:             |
   bb.0.entry:
     liveins: $x10, $x11, $x12
-    ; CHECK-LABEL: name: test_multiple_uses
-    ; CHECK: bb.0.entry:
-    ; CHECK-NEXT: liveins: $x10, $x11, $x12
     ; Test that variables with multiple uses have correct liveness ranges
 
+    ; CHECK-LABEL: name: test_multiple_uses
+    ; CHECK: liveins: $x10, $x11, $x12
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
+    ; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[COPY]], [[COPY1]]
+    ; CHECK-NEXT: [[MUL:%[0-9]+]]:gpr = MUL [[ADD]], [[COPY2]]
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:gpr = SUB [[MUL]], [[COPY]]
+    ; CHECK-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[SUB]], [[COPY1]]
+    ; CHECK-NEXT: $x10 = COPY [[ADD1]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
     %0:gpr = COPY $x10
     %1:gpr = COPY $x11
     %2:gpr = COPY $x12
diff --git a/llvm/test/CodeGen/RISCV/live-variables-edge-cases.ll b/llvm/test/CodeGen/RISCV/live-variables-edge-cases.ll
index 6cac878940969..08701f494f54d 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-edge-cases.ll
+++ b/llvm/test/CodeGen/RISCV/live-variables-edge-cases.ll
@@ -1,65 +1,75 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 ; RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs \
-; RUN: -riscv-enable-live-variables -riscv-liveness-update-kills -stop-after=riscv-live-variables \
+; RUN: -riscv-enable-live-variables -stop-after=sparse-live-variables \
 ; RUN: -o - %s | FileCheck %s
 
 ; Test live variable analysis edge cases and special scenarios
 ; Including: dead code, unreachable blocks, critical edges, and complex phi nodes
 
-; CHECK: test_dead_code
-; CHECK:   bb.0.entry:
-; CHECK:     liveins: $x10
-; CHECK:     %0:gpr = COPY $x10
-; CHECK:     $x10 = COPY killed %0
-; CHECK:     PseudoRET implicit $x10
 
 define i64 @test_dead_code(i64 %a, i64 %b) {
+  ; CHECK-LABEL: name: test_dead_code
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   liveins: $x10
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   $x10 = COPY [[COPY]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
 entry:
   %dead = add i64 %a, %b
   ret i64 %a
 }
 
-; CHECK: test_critical_edge
-; CHECK:  bb.0.entry:
-; CHECK:    successors: %bb.2(0x50000000), %bb.1(0x30000000)
-; CHECK:    liveins: $x10, $x11, $x12
 ;
-; CHECK:    %5:gpr = COPY $x12
-; CHECK:    %4:gpr = COPY $x11
-; CHECK:    %3:gpr = COPY $x10
-; CHECK:    %6:gpr = COPY $x0
-; CHECK:    BLT killed %6, %3, %bb.2
-; CHECK:    PseudoBR %bb.1
 ;
-; CHECK:  bb.1.check2:
-; CHECK:    successors: %bb.2(0x50000000), %bb.3(0x30000000)
 ;
-; CHECK:    %7:gpr = COPY $x0
-; CHECK:    BGE killed %7, %4, %bb.3
-; CHECK:    PseudoBR %bb.2
 ;
-; CHECK:  bb.2.then:
-; CHECK:    successors: %bb.4(0x80000000)
 ;
-; CHECK:    ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:    $x10 = COPY killed %3
-; CHECK:    $x11 = COPY killed %4
-; CHECK:    PseudoCALL target-flags(riscv-call) &__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
-; CHECK:    ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:    %8:gpr = COPY $x10
-; CHECK:    %0:gpr = COPY killed %8
-; CHECK:    PseudoBR %bb.4
 ;
-; CHECK:  bb.3.else:
-; CHECK:    successors: %bb.4(0x80000000)
 ;
-; CHECK:    %1:gpr = SUB killed %3, killed %5
 ;
-; CHECK:  bb.4.end:
-; CHECK:    %2:gpr = PHI %1, %bb.3, %0, %bb.2
-; CHECK:    $x10 = COPY killed %2
-; CHECK:    PseudoRET implicit $x10
 
 define i64 @test_critical_edge(i64 %a, i64 %b, i64 %c) {
+  ; CHECK-LABEL: name: test_critical_edge
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.2(0x50000000), %bb.1(0x30000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   BLT [[COPY3]], [[COPY2]], %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.check2:
+  ; CHECK-NEXT:   successors: %bb.2(0x50000000), %bb.3(0x30000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   BGE [[COPY4]], [[COPY1]], %bb.3
+  ; CHECK-NEXT:   PseudoBR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.then:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   $x10 = COPY [[COPY2]]
+  ; CHECK-NEXT:   $x11 = COPY [[COPY1]]
+  ; CHECK-NEXT:   PseudoCALL target-flags(riscv-call) &__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY6:%[0-9]+]]:gpr = COPY [[COPY5]]
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.else:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SUB:%[0-9]+]]:gpr = SUB [[COPY2]], [[COPY]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.end:
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[SUB]], %bb.3, [[COPY6]], %bb.2
+  ; CHECK-NEXT:   $x10 = COPY [[PHI]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
 entry:
   %cmp1 = icmp sgt i64 %a, 0
   br i1 %cmp1, label %then, label %check2
@@ -81,55 +91,65 @@ end:
   ret i64 %result
 }
 
-; CHECK: test_complex_phi
-; CHECK:   bb.0.entry:
-; CHECK:     successors: %bb.1(0x50000000), %bb.2(0x30000000)
-; CHECK:     liveins: $x10, $x11, $x12, $x13
 ;
-; CHECK:     %7:gpr = COPY $x13
-; CHECK:     %6:gpr = COPY $x12
-; CHECK:     %5:gpr = COPY $x11
-; CHECK:     %4:gpr = COPY $x10
-; CHECK:     %8:gpr = COPY $x0
-; CHECK:     BGE killed %8, %4, %bb.2
-; CHECK:     PseudoBR %bb.1
 ;
-; CHECK:   bb.1.path1:
-; CHECK:     successors: %bb.5(0x80000000)
 ;
-; CHECK:     %0:gpr = ADD killed %4, killed %5
-; CHECK:     PseudoBR %bb.5
 ;
-; CHECK:   bb.2.path2:
-; CHECK:     successors: %bb.3(0x50000000), %bb.4(0x30000000)
 ;
-; CHECK:     %9:gpr = COPY $x0
-; CHECK:     BGE killed %9, %6, %bb.4
-; CHECK:     PseudoBR %bb.3
 ;
-; CHECK:   bb.3.path2a:
-; CHECK:     successors: %bb.5(0x80000000)
 ;
-; CHECK:     ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:     $x10 = COPY killed %6
-; CHECK:     $x11 = COPY killed %7
-; CHECK:     PseudoCALL target-flags(riscv-call) &__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
-; CHECK:     ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:     %10:gpr = COPY $x10
-; CHECK:     %1:gpr = COPY killed %10
-; CHECK:     PseudoBR %bb.5
 ;
-; CHECK:   bb.4.path2b:
-; CHECK:     successors: %bb.5(0x80000000)
 ;
-; CHECK:     %2:gpr = SUB killed %6, killed %7
 ;
-; CHECK:   bb.5.merge:
-; CHECK:     %3:gpr = PHI %2, %bb.4, %1, %bb.3, %0, %bb.1
-; CHECK:     $x10 = COPY killed %3
-; CHECK:     PseudoRET implicit $x10
 
 define i64 @test_complex_phi(i64 %a, i64 %b, i64 %c, i64 %d) {
+  ; CHECK-LABEL: name: test_complex_phi
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x50000000), %bb.2(0x30000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12, $x13
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x13
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   BGE [[COPY4]], [[COPY3]], %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.path1:
+  ; CHECK-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[COPY3]], [[COPY2]]
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.path2:
+  ; CHECK-NEXT:   successors: %bb.3(0x50000000), %bb.4(0x30000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   BGE [[COPY5]], [[COPY1]], %bb.4
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.path2a:
+  ; CHECK-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   $x10 = COPY [[COPY1]]
+  ; CHECK-NEXT:   $x11 = COPY [[COPY]]
+  ; CHECK-NEXT:   PseudoCALL target-flags(riscv-call) &__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   [[COPY6:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY7:%[0-9]+]]:gpr = COPY [[COPY6]]
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.path2b:
+  ; CHECK-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SUB:%[0-9]+]]:gpr = SUB [[COPY1]], [[COPY]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.merge:
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[SUB]], %bb.4, [[COPY7]], %bb.3, [[ADD]], %bb.1
+  ; CHECK-NEXT:   $x10 = COPY [[PHI]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
 entry:
   %cmp1 = icmp sgt i64 %a, 0
   br i1 %cmp1, label %path1, label %path2
@@ -155,18 +175,19 @@ merge:
   ret i64 %result
 }
 
-; CHECK: test_use_after_def
-; CHECK:   bb.0.entry:
-; CHECK:     liveins: $x10
 ;
-; CHECK:     %0:gpr = COPY $x10
-; CHECK:     %1:gpr = ADDI killed %0, 1
-; CHECK:     %2:gpr = ADD killed %1, %1
-; CHECK:     %3:gpr = ADDI killed %2, 5
-; CHECK:     $x10 = COPY killed %3
-; CHECK:     PseudoRET implicit $x10
 
 define i64 @test_use_after_def(i64 %a) {
+  ; CHECK-LABEL: name: test_use_after_def
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   liveins: $x10
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[COPY]], 1
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[ADDI]], [[ADDI]]
+  ; CHECK-NEXT:   [[ADDI1:%[0-9]+]]:gpr = ADDI killed [[ADD]], 5
+  ; CHECK-NEXT:   $x10 = COPY [[ADDI1]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
 entry:
   %v1 = add i64 %a, 1
   %v2 = add i64 %v1, 2
@@ -175,29 +196,30 @@ entry:
   ret i64 %v4
 }
 
-; CHECK: test_implicit_defs
-; CHECK:   bb.0.entry:
-; CHECK:     liveins: $x10, $x11
-;
-; CHECK:     %1:gpr = COPY $x11
-; CHECK:     %0:gpr = COPY $x10
-; CHECK:     ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:     $x10 = COPY %0
-; CHECK:     $x11 = COPY %1
-; CHECK:     PseudoCALL target-flags(riscv-call) &__divdi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
-; CHECK:     ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:     %2:gpr = COPY $x10
-; CHECK:     ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:     $x10 = COPY killed %0
-; CHECK:     $x11 = COPY killed %1
-; CHECK:     PseudoCALL target-flags(riscv-call) &__moddi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
-; CHECK:     ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:     %3:gpr = COPY $x10
-; CHECK:     %4:gpr = ADD killed %2, killed %3
-; CHECK:     $x10 = COPY killed %4
-; CHECK:     PseudoRET implicit $x10
+;
 
 define i64 @test_implicit_defs(i64 %a, i64 %b) {
+  ; CHECK-LABEL: name: test_implicit_defs
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   liveins: $x10, $x11
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   $x10 = COPY [[COPY1]]
+  ; CHECK-NEXT:   $x11 = COPY [[COPY]]
+  ; CHECK-NEXT:   PseudoCALL target-flags(riscv-call) &__divdi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   $x10 = COPY [[COPY1]]
+  ; CHECK-NEXT:   $x11 = COPY [[COPY]]
+  ; CHECK-NEXT:   PseudoCALL target-flags(riscv-call) &__moddi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[COPY2]], [[COPY3]]
+  ; CHECK-NEXT:   $x10 = COPY [[ADD]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
 entry:
   %div = sdiv i64 %a, %b
   %rem = srem i64 %a, %b
diff --git a/llvm/test/CodeGen/RISCV/live-variables-loops.ll b/llvm/test/CodeGen/RISCV/live-variables-loops.ll
index 2cc0ff65c74b3..9e8408c1e0178 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-loops.ll
+++ b/llvm/test/CodeGen/RISCV/live-variables-loops.ll
@@ -1,35 +1,40 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 ; RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs \
-; RUN: -riscv-enable-live-variables -riscv-liveness-update-kills -stop-after=riscv-live-variables \
+; RUN: -riscv-enable-live-variables -stop-after=sparse-live-variables \
 ; RUN: -o - %s | FileCheck %s
 
 ; Test live variable analysis with loops and backward edges
 ; Loops create interesting liveness patterns with phi nodes and variables
 ; that are live across backedges
 
-; CHECK:  test_simple_loop
-; CHECK:  bb.0.entry:
-; CHECK:    successors: %bb.1(0x80000000)
-; CHECK:    liveins: $x10
-;
-; CHECK:    %4:gpr = COPY $x10
-; CHECK:    %6:gpr = COPY $x0
-; CHECK:    %5:gpr = COPY killed %6
-;
-; CHECK:  bb.1.loop:
-; CHECK:    successors: %bb.1(0x7c000000), %bb.2(0x04000000)
-;
-; CHECK:    %0:gpr = PHI %5, %bb.0, %3, %bb.1
-; CHECK:    %1:gpr = PHI %5, %bb.0, %2, %bb.1
-; CHECK:    %2:gpr = ADD killed %1, %0
-; CHECK:    %3:gpr = ADDI killed %0, 1
-; CHECK:    BLT %3, %4, %bb.1
-; CHECK:    PseudoBR %bb.2
-; 
-; CHECK:  bb.2.exit:
-; CHECK:    $x10 = COPY killed %2
-; CHECK:    PseudoRET implicit $x10
+;
+;
+;
+;
 
 define i64 @test_simple_loop(i64 %n) {
+  ; CHECK-LABEL: name: test_simple_loop
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY [[COPY1]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY2]], %bb.0, %3, %bb.1
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY2]], %bb.0, %2, %bb.1
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[PHI1]], [[PHI]]
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI]], 1
+  ; CHECK-NEXT:   BLT [[ADDI]], [[COPY]], %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[ADD]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
 entry:
   br label %loop
 
@@ -45,49 +50,57 @@ exit:
   ret i64 %sum.next
 }
 
-; CHECK:  test_nested_loop
-; CHECK:  bb.0.entry:
-; CHECK:    successors: %bb.1(0x80000000)
-; CHECK:    liveins: $x10, $x11
-;
-; CHECK:    %11:gpr = COPY $x11
-; CHECK:    %10:gpr = COPY $x10
-; CHECK:    %13:gpr = COPY $x0
-; CHECK:    %12:gpr = COPY killed %13
-;
-; CHECK:  bb.1.outer.loop:
-; CHECK:    successors: %bb.2(0x80000000)
-;
-; CHECK:    %0:gpr = PHI %12, %bb.0, %9, %bb.3
-; CHECK:    %1:gpr = PHI %12, %bb.0, %8, %bb.3
-; CHECK:    %15:gpr = COPY $x0
-; CHECK:    %14:gpr = COPY killed %15
-;
-; CHECK:  bb.2.inner.loop:
-; CHECK:    successors: %bb.2(0x7c000000), %bb.3(0x04000000)
-;
-; CHECK:    %2:gpr = PHI %14, %bb.1, %7, %bb.2
-; CHECK:    %3:gpr = PHI %14, %bb.1, %6, %bb.2
-; CHECK:    %4:gpr = PHI %14, %bb.1, %5, %bb.2
-; CHECK:    %5:gpr = ADD %4, %2
-; CHECK:    %6:gpr = ADDI killed %3, 1
-; CHECK:    %7:gpr = ADD killed %2, %0
-; CHECK:    BLT %6, %11, %bb.2
-; CHECK:    PseudoBR %bb.3
-;
-; CHECK:  bb.3.outer.latch:
-; CHECK:    successors: %bb.1(0x7c000000), %bb.4(0x04000000)
-;
-; CHECK:    %8:gpr = ADD killed %1, %5
-; CHECK:    %9:gpr = ADDI killed %0, 1
-; CHECK:    BLT %9, %10, %bb.1
-; CHECK:    PseudoBR %bb.4
-;
-; CHECK:  bb.4.exit:
-; CHECK:    $x10 = COPY killed %8
-; CHECK:    PseudoRET implicit $x10
+;
+;
+;
+;
+;
+;
+;
+;
 
 define i64 @test_nested_loop(i64 %n, i64 %m) {
+  ; CHECK-LABEL: name: test_nested_loop
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY [[COPY2]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.outer.loop:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY3]], %bb.0, %9, %bb.3
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY3]], %bb.0, %8, %bb.3
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:gpr = COPY [[COPY4]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.inner.loop:
+  ; CHECK-NEXT:   successors: %bb.2(0x7c000000), %bb.3(0x04000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[COPY5]], %bb.1, %7, %bb.2
+  ; CHECK-NEXT:   [[PHI3:%[0-9]+]]:gpr = PHI [[COPY5]], %bb.1, %6, %bb.2
+  ; CHECK-NEXT:   [[PHI4:%[0-9]+]]:gpr = PHI [[COPY5]], %bb.1, %5, %bb.2
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[PHI4]], [[PHI2]]
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI3]], 1
+  ; CHECK-NEXT:   [[ADD1:%[0-9]+]]:gpr = ADD [[PHI2]], [[PHI]]
+  ; CHECK-NEXT:   BLT [[ADDI]], [[COPY]], %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.outer.latch:
+  ; CHECK-NEXT:   successors: %bb.1(0x7c000000), %bb.4(0x04000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADD2:%[0-9]+]]:gpr = ADD [[PHI1]], [[ADD]]
+  ; CHECK-NEXT:   [[ADDI1:%[0-9]+]]:gpr = ADDI [[PHI]], 1
+  ; CHECK-NEXT:   BLT [[ADDI1]], [[COPY1]], %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[ADD2]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
 entry:
   br label %outer.loop
 
@@ -115,34 +128,38 @@ exit:
   ret i64 %new.outer.sum
 }
 
-; CHECK:  test_loop_with_invariant
-; CHECK:  bb.0.entry:
-; CHECK:    successors: %bb.1(0x80000000)
-; CHECK:    liveins: $x10, $x11
-;
-; CHECK:    %8:gpr = COPY $x11
-; CHECK:    %7:gpr = COPY $x10
-; CHECK:    %0:gpr = SLLI killed %8, 1
-; CHECK:    %10:gpr = COPY $x0
-; CHECK:    %9:gpr = COPY killed %10
-;
-; CHECK:  bb.1.loop:
-; CHECK:    successors: %bb.1(0x7c000000), %bb.2(0x04000000)
-;
-; CHECK:    %1:gpr = PHI %9, %bb.0, %6, %bb.1
-; CHECK:    %2:gpr = PHI %9, %bb.0, %5, %bb.1
-; CHECK:    %3:gpr = PHI %9, %bb.0, %4, %bb.1
-; CHECK:    %4:gpr = ADD killed %3, %1
-; CHECK:    %5:gpr = ADDI killed %2, 1
-; CHECK:    %6:gpr = ADD killed %1, %0
-; CHECK:    BLT %5, %7, %bb.1
-; CHECK:    PseudoBR %bb.2
-;
-; CHECK:  bb.2.exit:
-; CHECK:    $x10 = COPY killed %4
-; CHECK:    PseudoRET implicit $x10
+;
+;
+;
+;
 
 define i64 @test_loop_with_invariant(i64 %n, i64 %k) {
+  ; CHECK-LABEL: name: test_loop_with_invariant
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[SLLI:%[0-9]+]]:gpr = SLLI [[COPY]], 1
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY [[COPY2]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY3]], %bb.0, %6, %bb.1
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY3]], %bb.0, %5, %bb.1
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[COPY3]], %bb.0, %4, %bb.1
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[PHI2]], [[PHI]]
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI1]], 1
+  ; CHECK-NEXT:   [[ADD1:%[0-9]+]]:gpr = ADD [[PHI]], [[SLLI]]
+  ; CHECK-NEXT:   BLT [[ADDI]], [[COPY1]], %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[ADD]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
 entry:
   %double_k = mul i64 %k, 2
   br label %loop
diff --git a/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll b/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll
index 547ba6ee764d9..2da682e14c35a 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll
+++ b/llvm/test/CodeGen/RISCV/live-variables-mbb-liveins.ll
@@ -1,53 +1,96 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 ; Pre-regalloc test
 ; RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs \
-; RUN: -riscv-liveness-update-kills -stop-after=riscv-live-variables \
-; RUN: -riscv-liveness-update-mbb-liveins < %s | FileCheck %s
+; RUN: -stop-after=sparse-live-variables \
+; RUN: < %s | FileCheck %s
 
 ; Post-regalloc test
 ; RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs \
-; RUN: -riscv-liveness-update-kills -stop-after=riscv-live-variables,1 \
-; RUN: -riscv-liveness-update-mbb-liveins < %s | FileCheck %s --check-prefix=CHECK-PR
+; RUN: -stop-after=sparse-live-variables,1 \
+; RUN: < %s | FileCheck %s --check-prefix=CHECK-PR
 
 ; Basic test: simple function with two arguments
-; CHECK-LABEL: name: test_mbb_liveins
-; CHECK: bb.0.entry:
-; CHECK:   liveins: $x10, $x11
-; CHECK:   %1:gpr = COPY $x11
-; CHECK:   %0:gpr = COPY $x10
-; CHECK:   %2:gpr = ADD killed %0, killed %1
-; CHECK:   $x10 = COPY killed %2
-; CHECK:   PseudoRET implicit $x10
 
 define i64 @test_mbb_liveins(i64 %a, i64 %b) {
+  ; CHECK-LABEL: name: test_mbb_liveins
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   liveins: $x10, $x11
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[COPY1]], [[COPY]]
+  ; CHECK-NEXT:   $x10 = COPY [[ADD]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ;
+  ; CHECK-PR-LABEL: name: test_mbb_liveins
+  ; CHECK-PR: bb.0.entry:
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x10 = ADD killed renamable $x10, killed renamable $x11
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
 entry:
   %sum = add i64 %a, %b
   ret i64 %sum
 }
 
 ; Test with control flow: verify live-ins are correct for entry block with multiple args
-; CHECK-PR-LABEL: name{{.*}}test_control_flow
-; CHECK-PR: bb.0.entry:
-; CHECK-PR:   successors:
-; CHECK-PR:   liveins: $x10, $x11, $x12
-; CHECK-PR:   BNE killed renamable $x12, killed $x0, %bb.2
-; CHECK-PR:   PseudoBR %bb.1
-
-; CHECK-PR: bb.1.then:
-; CHECK-PR:   successors:
-; CHECK-PR:   liveins: $x10, $x11
-; CHECK-PR:   renamable $x10 = ADD killed renamable $x10, killed renamable $x11
-; CHECK-PR:   PseudoBR %bb.3
-
-; CHECK-PR: bb.2.else:
-; CHECK-PR:   successors:
-; CHECK-PR:   liveins: $x10, $x11
-; CHECK-PR:   renamable $x10 = SUB killed renamable $x10, killed renamable $x11
-
-; CHECK-PR: bb.3.end:
-; CHECK-PR:   liveins: $x10
-; CHECK-PR:   PseudoRET implicit killed $x10
+
+
+
 
 define i64 @test_control_flow(i64 %a, i64 %b, i64 %cond) {
+  ; CHECK-LABEL: name: test_control_flow
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x30000000), %bb.2(0x50000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   BNE [[COPY]], $x0, %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.then:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[COPY2]], [[COPY1]]
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.else:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SUB:%[0-9]+]]:gpr = SUB [[COPY2]], [[COPY1]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.end:
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[SUB]], %bb.2, [[ADD]], %bb.1
+  ; CHECK-NEXT:   $x10 = COPY [[PHI]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ;
+  ; CHECK-PR-LABEL: name: test_control_flow
+  ; CHECK-PR: bb.0.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x30000000), %bb.2(0x50000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   BNE killed renamable $x12, $x0, %bb.2
+  ; CHECK-PR-NEXT:   PseudoBR %bb.1
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.1.then:
+  ; CHECK-PR-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x10 = ADD killed renamable $x10, killed renamable $x11
+  ; CHECK-PR-NEXT:   PseudoBR %bb.3
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.2.else:
+  ; CHECK-PR-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x10 = SUB killed renamable $x10, killed renamable $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.3.end:
+  ; CHECK-PR-NEXT:   liveins: $x10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
 entry:
   %cmp = icmp eq i64 %cond, 0
   br i1 %cmp, label %then, label %else
@@ -66,15 +109,49 @@ end:
 }
 
 ; Test with loops: verify live-ins for loop headers
-; CHECK-LABEL: name: test_loop
-; CHECK: bb.0.entry:
-; CHECK:   liveins: $x10
-; CHECK: bb.1.loop:
-; CHECK-NOT: liveins:
-; CHECK: bb.2.exit:
-; CHECK-NOT: liveins:
 
 define i64 @test_loop(i64 %n) {
+  ; CHECK-LABEL: name: test_loop
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY [[COPY1]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY2]], %bb.0, %1, %bb.1
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI]], 1
+  ; CHECK-NEXT:   BLTU [[ADDI]], [[COPY]], %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[ADDI]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ;
+  ; CHECK-PR-LABEL: name: test_loop
+  ; CHECK-PR: bb.0.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x11 = COPY $x0
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.1.loop:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x11 = ADDI killed renamable $x11, 1
+  ; CHECK-PR-NEXT:   BLTU renamable $x11, renamable $x10, %bb.1
+  ; CHECK-PR-NEXT:   PseudoBR %bb.2
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.2.exit:
+  ; CHECK-PR-NEXT:   liveins: $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   $x10 = COPY killed renamable $x11
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
 entry:
   br label %loop
 
@@ -90,16 +167,31 @@ exit:
 
 ; Test that reserved registers (like $x2 stack pointer) are NOT in live-ins
 ; This test uses function calls which implicitly use $x2 for stack operations
-; CHECK-LABEL: name: test_reserved_regs
-; CHECK: bb.0.entry:
-; CHECK:   liveins: $x10, $x11
-; CHECK-NOT:   liveins: {{.*}}$x2
-; CHECK:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:   $x10 = COPY killed %0
-; CHECK:   $x11 = COPY killed %1
-; CHECK:   PseudoCALL target-flags(riscv-call) @__adddi3
 
 define i64 @test_reserved_regs(i64 %a, i64 %b) {
+  ; CHECK-LABEL: name: test_reserved_regs
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   liveins: $x10, $x11
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   $x10 = COPY [[COPY1]]
+  ; CHECK-NEXT:   $x11 = COPY [[COPY]]
+  ; CHECK-NEXT:   PseudoCALL target-flags(riscv-call) @__adddi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   $x10 = COPY [[COPY2]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ;
+  ; CHECK-PR-LABEL: name: test_reserved_regs
+  ; CHECK-PR: bb.0.entry:
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-PR-NEXT:   PseudoCALL target-flags(riscv-call) @__adddi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-PR-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
 entry:
   %sum = call i64 @__adddi3(i64 %a, i64 %b)
   ret i64 %sum
@@ -108,15 +200,30 @@ entry:
 declare i64 @__adddi3(i64, i64)
 
 ; Test with multiple arguments to verify all live-ins are tracked
-; CHECK-LABEL: name: test_many_args
-; CHECK: bb.0.entry:
-; CHECK:   liveins: $x10, $x11, $x12, $x13
-; CHECK:   %3:gpr = COPY $x13
-; CHECK:   %2:gpr = COPY $x12
-; CHECK:   %1:gpr = COPY $x11
-; CHECK:   %0:gpr = COPY $x10
 
 define i64 @test_many_args(i64 %a, i64 %b, i64 %c, i64 %d) {
+  ; CHECK-LABEL: name: test_many_args
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12, $x13
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x13
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[COPY3]], [[COPY2]]
+  ; CHECK-NEXT:   [[ADD1:%[0-9]+]]:gpr = ADD [[COPY1]], [[COPY]]
+  ; CHECK-NEXT:   [[ADD2:%[0-9]+]]:gpr = ADD killed [[ADD]], killed [[ADD1]]
+  ; CHECK-NEXT:   $x10 = COPY [[ADD2]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ;
+  ; CHECK-PR-LABEL: name: test_many_args
+  ; CHECK-PR: bb.0.entry:
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12, $x13
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x10 = ADD killed renamable $x10, killed renamable $x11
+  ; CHECK-PR-NEXT:   renamable $x12 = ADD killed renamable $x12, killed renamable $x13
+  ; CHECK-PR-NEXT:   renamable $x10 = ADD killed renamable $x10, killed renamable $x12
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
 entry:
   %sum1 = add i64 %a, %b
   %sum2 = add i64 %c, %d
@@ -125,11 +232,86 @@ entry:
 }
 
 ; Test with nested control flow to ensure entry block has correct live-ins
-; CHECK-LABEL: name: test_nested_control_flow
-; CHECK: bb.0.entry:
-; CHECK:   liveins: $x10, $x11, $x12
 
 define i64 @test_nested_control_flow(i64 %a, i64 %b, i64 %c) {
+  ; CHECK-LABEL: name: test_nested_control_flow
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x30000000), %bb.4(0x50000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   BNE [[COPY]], $x0, %bb.4
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.outer_then:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   BGE [[COPY1]], [[COPY2]], %bb.3
+  ; CHECK-NEXT:   PseudoBR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.inner_then:
+  ; CHECK-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[COPY2]], [[COPY1]]
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.inner_else:
+  ; CHECK-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SUB:%[0-9]+]]:gpr = SUB [[COPY2]], [[COPY1]]
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.outer_else:
+  ; CHECK-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SLLI:%[0-9]+]]:gpr = SLLI [[COPY2]], 1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.end:
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[SLLI]], %bb.4, [[SUB]], %bb.3, [[ADD]], %bb.2
+  ; CHECK-NEXT:   $x10 = COPY [[PHI]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ;
+  ; CHECK-PR-LABEL: name: test_nested_control_flow
+  ; CHECK-PR: bb.0.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x30000000), %bb.4(0x50000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   BNE killed renamable $x12, $x0, %bb.4
+  ; CHECK-PR-NEXT:   PseudoBR %bb.1
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.1.outer_then:
+  ; CHECK-PR-NEXT:   successors: %bb.2(0x40000000), %bb.3(0x40000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   BGE renamable $x11, renamable $x10, %bb.3
+  ; CHECK-PR-NEXT:   PseudoBR %bb.2
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.2.inner_then:
+  ; CHECK-PR-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x10 = ADD killed renamable $x10, killed renamable $x11
+  ; CHECK-PR-NEXT:   PseudoBR %bb.5
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.3.inner_else:
+  ; CHECK-PR-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x10 = SUB killed renamable $x10, killed renamable $x11
+  ; CHECK-PR-NEXT:   PseudoBR %bb.5
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.4.outer_else:
+  ; CHECK-PR-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x10 = SLLI killed renamable $x10, 1
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.5.end:
+  ; CHECK-PR-NEXT:   liveins: $x10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
 entry:
   %cmp1 = icmp eq i64 %c, 0
   br i1 %cmp1, label %outer_then, label %outer_else
@@ -156,11 +338,94 @@ end:
 }
 
 ; Test with doubly nested loops
-; CHECK-LABEL: name: test_doubly_nested_loop
-; CHECK: bb.0.entry:
-; CHECK:   liveins: $x10, $x11
 
 define i64 @test_doubly_nested_loop(i64 %n, i64 %m) {
+  ; CHECK-LABEL: name: test_doubly_nested_loop
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY [[COPY2]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.outer_loop:
+  ; CHECK-NEXT:   successors: %bb.2(0x7c000000), %bb.5(0x04000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY3]], %bb.0, %6, %bb.4
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY3]], %bb.0, %4, %bb.4
+  ; CHECK-NEXT:   BGEU [[PHI]], [[COPY1]], %bb.5
+  ; CHECK-NEXT:   PseudoBR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.inner_loop.preheader:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:gpr = COPY [[COPY4]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.inner_loop:
+  ; CHECK-NEXT:   successors: %bb.3(0x7c000000), %bb.4(0x04000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[COPY5]], %bb.2, %5, %bb.3
+  ; CHECK-NEXT:   [[PHI3:%[0-9]+]]:gpr = PHI [[PHI1]], %bb.2, %4, %bb.3
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[PHI3]], [[PHI2]]
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI2]], 1
+  ; CHECK-NEXT:   BLTU [[ADDI]], [[COPY]], %bb.3
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.outer_latch:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADDI1:%[0-9]+]]:gpr = ADDI [[PHI]], 1
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[PHI1]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ;
+  ; CHECK-PR-LABEL: name: test_doubly_nested_loop
+  ; CHECK-PR: bb.0.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x13 = COPY $x0
+  ; CHECK-PR-NEXT:   renamable $x12 = COPY $x0
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.1.outer_loop:
+  ; CHECK-PR-NEXT:   successors: %bb.2(0x7c000000), %bb.5(0x04000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12, $x13
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   BGEU renamable $x13, renamable $x10, %bb.5
+  ; CHECK-PR-NEXT:   PseudoBR %bb.2
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.2.inner_loop.preheader:
+  ; CHECK-PR-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12, $x13
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x14 = COPY $x0
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.3.inner_loop:
+  ; CHECK-PR-NEXT:   successors: %bb.3(0x7c000000), %bb.4(0x04000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x12 = ADD killed renamable $x12, renamable $x14
+  ; CHECK-PR-NEXT:   renamable $x14 = ADDI killed renamable $x14, 1
+  ; CHECK-PR-NEXT:   BLTU renamable $x14, renamable $x11, %bb.3
+  ; CHECK-PR-NEXT:   PseudoBR %bb.4
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.4.outer_latch:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12, $x13
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x13 = ADDI killed renamable $x13, 1
+  ; CHECK-PR-NEXT:   PseudoBR %bb.1
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.5.exit:
+  ; CHECK-PR-NEXT:   liveins: $x12
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   $x10 = COPY killed renamable $x12
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
 entry:
   br label %outer_loop
 
@@ -189,12 +454,149 @@ exit:
 
 ; Test with triply nested loops and function calls
 ; This tests that reserved registers ($x2) are not added to live-ins even with deep nesting
-; CHECK-LABEL: name: test_triply_nested_loop_with_calls
-; CHECK: bb.0.entry:
-; CHECK:   liveins: $x10, $x11, $x12
-; CHECK-NOT:   liveins: {{.*}}$x2
 
 define i64 @test_triply_nested_loop_with_calls(i64 %n, i64 %m, i64 %p) {
+  ; CHECK-LABEL: name: test_triply_nested_loop_with_calls
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:gpr = COPY [[COPY3]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop_i:
+  ; CHECK-NEXT:   successors: %bb.2(0x7c000000), %bb.8(0x04000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY4]], %bb.0, %9, %bb.7
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY4]], %bb.0, %3, %bb.7
+  ; CHECK-NEXT:   BGEU [[PHI]], [[COPY2]], %bb.8
+  ; CHECK-NEXT:   PseudoBR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.loop_j_header:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   [[COPY6:%[0-9]+]]:gpr = COPY [[COPY5]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.loop_j:
+  ; CHECK-NEXT:   successors: %bb.4(0x7c000000), %bb.7(0x04000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[COPY6]], %bb.2, %8, %bb.6
+  ; CHECK-NEXT:   [[PHI3:%[0-9]+]]:gpr = PHI [[PHI1]], %bb.2, %6, %bb.6
+  ; CHECK-NEXT:   BGEU [[PHI2]], [[COPY1]], %bb.7
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.loop_k_header:
+  ; CHECK-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY7:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   [[COPY8:%[0-9]+]]:gpr = COPY [[COPY7]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.loop_k:
+  ; CHECK-NEXT:   successors: %bb.5(0x7c000000), %bb.6(0x04000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI4:%[0-9]+]]:gpr = PHI [[COPY8]], %bb.4, %7, %bb.5
+  ; CHECK-NEXT:   [[PHI5:%[0-9]+]]:gpr = PHI [[PHI3]], %bb.4, %6, %bb.5
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   $x10 = COPY [[PHI]]
+  ; CHECK-NEXT:   $x11 = COPY [[PHI2]]
+  ; CHECK-NEXT:   PseudoCALL target-flags(riscv-call) @__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   [[COPY9:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[PHI5]], [[COPY9]]
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI4]], 1
+  ; CHECK-NEXT:   BLTU [[ADDI]], [[COPY]], %bb.5
+  ; CHECK-NEXT:   PseudoBR %bb.6
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.6.loop_k_exit:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADDI1:%[0-9]+]]:gpr = ADDI [[PHI2]], 1
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.7.loop_j_exit:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADDI2:%[0-9]+]]:gpr = ADDI [[PHI]], 1
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.8.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[PHI1]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ;
+  ; CHECK-PR-LABEL: name: test_triply_nested_loop_with_calls
+  ; CHECK-PR: bb.0.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x8 = COPY $x12
+  ; CHECK-PR-NEXT:   renamable $x9 = COPY $x11
+  ; CHECK-PR-NEXT:   renamable $x18 = COPY $x10
+  ; CHECK-PR-NEXT:   renamable $x20 = COPY $x0
+  ; CHECK-PR-NEXT:   renamable $x19 = COPY $x0
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.1.loop_i:
+  ; CHECK-PR-NEXT:   successors: %bb.2(0x7c000000), %bb.8(0x04000000)
+  ; CHECK-PR-NEXT:   liveins: $x8, $x9, $x18, $x19, $x20
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   BGEU renamable $x20, renamable $x18, %bb.8
+  ; CHECK-PR-NEXT:   PseudoBR %bb.2
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.2.loop_j_header:
+  ; CHECK-PR-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x8, $x9, $x18, $x19, $x20
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x21 = COPY $x0
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.3.loop_j:
+  ; CHECK-PR-NEXT:   successors: %bb.4(0x7c000000), %bb.7(0x04000000)
+  ; CHECK-PR-NEXT:   liveins: $x8, $x9, $x18, $x19, $x20, $x21
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   BGEU renamable $x21, renamable $x9, %bb.7
+  ; CHECK-PR-NEXT:   PseudoBR %bb.4
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.4.loop_k_header:
+  ; CHECK-PR-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x8, $x9, $x18, $x19, $x20, $x21
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x22 = COPY $x0
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.5.loop_k:
+  ; CHECK-PR-NEXT:   successors: %bb.5(0x7c000000), %bb.6(0x04000000)
+  ; CHECK-PR-NEXT:   liveins: $x8, $x9, $x18, $x19, $x20, $x21, $x22
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-PR-NEXT:   $x10 = COPY renamable $x20
+  ; CHECK-PR-NEXT:   $x11 = COPY renamable $x21
+  ; CHECK-PR-NEXT:   PseudoCALL target-flags(riscv-call) @__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-PR-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-PR-NEXT:   renamable $x22 = ADDI killed renamable $x22, 1
+  ; CHECK-PR-NEXT:   renamable $x19 = ADD killed renamable $x19, killed renamable $x10
+  ; CHECK-PR-NEXT:   BLTU renamable $x22, renamable $x8, %bb.5
+  ; CHECK-PR-NEXT:   PseudoBR %bb.6
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.6.loop_k_exit:
+  ; CHECK-PR-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x8, $x9, $x18, $x19, $x20, $x21
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x21 = ADDI killed renamable $x21, 1
+  ; CHECK-PR-NEXT:   PseudoBR %bb.3
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.7.loop_j_exit:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x8, $x9, $x18, $x19, $x20
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x20 = ADDI killed renamable $x20, 1
+  ; CHECK-PR-NEXT:   PseudoBR %bb.1
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.8.exit:
+  ; CHECK-PR-NEXT:   liveins: $x19
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   $x10 = COPY killed renamable $x19
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
 entry:
   br label %loop_i
 
@@ -251,11 +653,92 @@ exit:
 declare i64 @__muldi3(i64, i64)
 
 ; Test with unstructured control flow (multiple entries, irreducible loop)
-; CHECK-LABEL: name: test_unstructured_cfg
-; CHECK: bb.0.entry:
-; CHECK:   liveins: $x10, $x11, $x12
 
 define i64 @test_unstructured_cfg(i64 %a, i64 %b, i64 %selector) {
+  ; CHECK-LABEL: name: test_unstructured_cfg
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x30000000), %bb.2(0x50000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   BNE [[COPY]], $x0, %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.block_a:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[COPY2]], 1
+  ; CHECK-NEXT:   [[ADDI1:%[0-9]+]]:gpr = ADDI $x0, 9
+  ; CHECK-NEXT:   BLT killed [[ADDI1]], [[ADDI]], %bb.3
+  ; CHECK-NEXT:   PseudoBR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.block_b:
+  ; CHECK-NEXT:   successors: %bb.4(0x04000000), %bb.3(0x7c000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY1]], %bb.0, [[ADDI]], %bb.1, %4, %bb.3
+  ; CHECK-NEXT:   [[SLLI:%[0-9]+]]:gpr = SLLI [[PHI]], 1
+  ; CHECK-NEXT:   [[ADDI2:%[0-9]+]]:gpr = ADDI $x0, 100
+  ; CHECK-NEXT:   BLT killed [[ADDI2]], [[SLLI]], %bb.4
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.block_c:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.1(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[ADDI]], %bb.1, [[SLLI]], %bb.2
+  ; CHECK-NEXT:   [[ADDI3:%[0-9]+]]:gpr = ADDI [[PHI1]], -1
+  ; CHECK-NEXT:   [[ADDI4:%[0-9]+]]:gpr = ADDI $x0, 5
+  ; CHECK-NEXT:   BLTU killed [[ADDI4]], [[ADDI3]], %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[SLLI]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ;
+  ; CHECK-PR-LABEL: name: test_unstructured_cfg
+  ; CHECK-PR: bb.0.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x30000000), %bb.2(0x50000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   BNE killed renamable $x12, $x0, %bb.2
+  ; CHECK-PR-NEXT:   PseudoBR %bb.1
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.1.block_a:
+  ; CHECK-PR-NEXT:   successors: %bb.2(0x40000000), %bb.3(0x40000000)
+  ; CHECK-PR-NEXT:   liveins: $x10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x11 = ADDI renamable $x10, 1
+  ; CHECK-PR-NEXT:   renamable $x12 = ADDI $x0, 9
+  ; CHECK-PR-NEXT:   BLT killed renamable $x12, renamable $x11, %bb.3
+  ; CHECK-PR-NEXT:   PseudoBR %bb.2
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.2.block_b:
+  ; CHECK-PR-NEXT:   successors: %bb.4(0x04000000), %bb.5(0x7c000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x11 = SLLI killed renamable $x11, 1
+  ; CHECK-PR-NEXT:   renamable $x12 = ADDI $x0, 100
+  ; CHECK-PR-NEXT:   BLT killed renamable $x12, renamable $x11, %bb.4
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.5:
+  ; CHECK-PR-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.3.block_c:
+  ; CHECK-PR-NEXT:   successors: %bb.2(0x40000000), %bb.1(0x40000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x11 = ADDI killed renamable $x11, -1
+  ; CHECK-PR-NEXT:   renamable $x12 = ADDI $x0, 5
+  ; CHECK-PR-NEXT:   BLTU killed renamable $x12, renamable $x11, %bb.2
+  ; CHECK-PR-NEXT:   PseudoBR %bb.1
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.4.exit:
+  ; CHECK-PR-NEXT:   liveins: $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   $x10 = COPY killed renamable $x11
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
 entry:
   %cmp1 = icmp eq i64 %selector, 0
   br i1 %cmp1, label %block_a, label %block_b
@@ -284,12 +767,106 @@ exit:
 
 ; Test with multiple function calls and complex control flow
 ; Ensures reserved registers are not in live-ins across multiple call sites
-; CHECK-LABEL: name: test_multiple_calls
-; CHECK: bb.0.entry:
-; CHECK:   liveins: $x10, $x11, $x12, $x13
-; CHECK-NOT:   liveins: {{.*}}$x2
 
 define i64 @test_multiple_calls(i64 %a, i64 %b, i64 %c, i64 %d) {
+  ; CHECK-LABEL: name: test_multiple_calls
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.2(0x40000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12, $x13
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x13
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   BGE [[COPY2]], [[COPY3]], %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.call1:
+  ; CHECK-NEXT:   successors: %bb.3(0x30000000), %bb.4(0x50000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   $x10 = COPY [[COPY3]]
+  ; CHECK-NEXT:   $x11 = COPY [[COPY2]]
+  ; CHECK-NEXT:   PseudoCALL target-flags(riscv-call) @__adddi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:gpr = COPY [[COPY4]]
+  ; CHECK-NEXT:   BEQ [[COPY4]], $x0, %bb.3
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.call2:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   $x10 = COPY [[COPY1]]
+  ; CHECK-NEXT:   $x11 = COPY [[COPY]]
+  ; CHECK-NEXT:   PseudoCALL target-flags(riscv-call) @__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   [[COPY6:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY7:%[0-9]+]]:gpr = COPY [[COPY6]]
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.call3:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   $x10 = COPY [[COPY1]]
+  ; CHECK-NEXT:   $x11 = COPY [[COPY]]
+  ; CHECK-NEXT:   PseudoCALL target-flags(riscv-call) @__adddi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   [[COPY8:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY9:%[0-9]+]]:gpr = COPY [[COPY8]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.merge:
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY7]], %bb.2, [[COPY5]], %bb.1, [[COPY9]], %bb.3
+  ; CHECK-NEXT:   $x10 = COPY [[PHI]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ;
+  ; CHECK-PR-LABEL: name: test_multiple_calls
+  ; CHECK-PR: bb.0.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x40000000), %bb.2(0x40000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12, $x13
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   BGE renamable $x11, renamable $x10, %bb.2
+  ; CHECK-PR-NEXT:   PseudoBR %bb.1
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.1.call1:
+  ; CHECK-PR-NEXT:   successors: %bb.3(0x30000000), %bb.4(0x50000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12, $x13
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x9 = COPY killed renamable $x12
+  ; CHECK-PR-NEXT:   renamable $x8 = COPY killed renamable $x13
+  ; CHECK-PR-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-PR-NEXT:   PseudoCALL target-flags(riscv-call) @__adddi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-PR-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-PR-NEXT:   BEQ renamable $x10, $x0, %bb.3
+  ; CHECK-PR-NEXT:   PseudoBR %bb.4
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.2.call2:
+  ; CHECK-PR-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x12, $x13
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-PR-NEXT:   $x10 = COPY killed renamable $x12
+  ; CHECK-PR-NEXT:   $x11 = COPY killed renamable $x13
+  ; CHECK-PR-NEXT:   PseudoCALL target-flags(riscv-call) @__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-PR-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-PR-NEXT:   PseudoBR %bb.4
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.3.call3:
+  ; CHECK-PR-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x8, $x9
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-PR-NEXT:   $x10 = COPY killed renamable $x9
+  ; CHECK-PR-NEXT:   $x11 = COPY killed renamable $x8
+  ; CHECK-PR-NEXT:   PseudoCALL target-flags(riscv-call) @__adddi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-PR-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.4.merge:
+  ; CHECK-PR-NEXT:   liveins: $x10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
 entry:
   %cmp = icmp sgt i64 %a, %b
   br i1 %cmp, label %call1, label %call2
@@ -313,11 +890,158 @@ merge:
 }
 
 ; Test with switch-like control flow
-; CHECK-LABEL: name: test_switch_cfg
-; CHECK: bb.0.entry:
-; CHECK:   liveins: $x10, $x11
 
 define i64 @test_switch_cfg(i64 %selector, i64 %value) {
+  ; CHECK-LABEL: name: test_switch_cfg
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.7(0x40000000), %bb.8(0x40000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+  ; CHECK-NEXT:   BLT killed [[ADDI]], [[COPY1]], %bb.8
+  ; CHECK-NEXT:   PseudoBR %bb.7
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.7.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x33333333), %bb.10(0x4ccccccd)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   BEQ [[COPY1]], $x0, %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.10
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.10.entry:
+  ; CHECK-NEXT:   successors: %bb.2(0x55555555), %bb.5(0x2aaaaaab)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADDI1:%[0-9]+]]:gpr = ADDI $x0, 1
+  ; CHECK-NEXT:   BEQ [[COPY1]], killed [[ADDI1]], %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.8.entry:
+  ; CHECK-NEXT:   successors: %bb.3(0x33333333), %bb.9(0x4ccccccd)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADDI2:%[0-9]+]]:gpr = ADDI $x0, 2
+  ; CHECK-NEXT:   BEQ [[COPY1]], killed [[ADDI2]], %bb.3
+  ; CHECK-NEXT:   PseudoBR %bb.9
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.9.entry:
+  ; CHECK-NEXT:   successors: %bb.4(0x55555555), %bb.5(0x2aaaaaab)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADDI3:%[0-9]+]]:gpr = ADDI $x0, 3
+  ; CHECK-NEXT:   BEQ [[COPY1]], killed [[ADDI3]], %bb.4
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.case0:
+  ; CHECK-NEXT:   successors: %bb.6(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADDI4:%[0-9]+]]:gpr = ADDI [[COPY]], 10
+  ; CHECK-NEXT:   PseudoBR %bb.6
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.case1:
+  ; CHECK-NEXT:   successors: %bb.6(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADDI5:%[0-9]+]]:gpr = ADDI [[COPY]], -10
+  ; CHECK-NEXT:   PseudoBR %bb.6
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.case2:
+  ; CHECK-NEXT:   successors: %bb.6(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SLLI:%[0-9]+]]:gpr = SLLI [[COPY]], 1
+  ; CHECK-NEXT:   PseudoBR %bb.6
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.case3:
+  ; CHECK-NEXT:   successors: %bb.6(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SLLI1:%[0-9]+]]:gpr = SLLI [[COPY]], 1
+  ; CHECK-NEXT:   PseudoBR %bb.6
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.default:
+  ; CHECK-NEXT:   successors: %bb.6(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY [[COPY2]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.6.exit:
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[SLLI1]], %bb.4, [[SLLI]], %bb.3, [[ADDI5]], %bb.2, [[ADDI4]], %bb.1, [[COPY3]], %bb.5
+  ; CHECK-NEXT:   $x10 = COPY [[PHI]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ;
+  ; CHECK-PR-LABEL: name: test_switch_cfg
+  ; CHECK-PR: bb.0.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x40000000), %bb.3(0x40000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x12 = ADDI $x0, 1
+  ; CHECK-PR-NEXT:   BLT killed renamable $x12, renamable $x10, %bb.3
+  ; CHECK-PR-NEXT:   PseudoBR %bb.1
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.1.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.5(0x33333333), %bb.2(0x4ccccccd)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   BEQ renamable $x10, $x0, %bb.5
+  ; CHECK-PR-NEXT:   PseudoBR %bb.2
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.2.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.6(0x55555555), %bb.9(0x2aaaaaab)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x12 = ADDI $x0, 1
+  ; CHECK-PR-NEXT:   BEQ killed renamable $x10, killed renamable $x12, %bb.6
+  ; CHECK-PR-NEXT:   PseudoBR %bb.9
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.3.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.7(0x33333333), %bb.4(0x4ccccccd)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x12 = ADDI $x0, 2
+  ; CHECK-PR-NEXT:   BEQ renamable $x10, killed renamable $x12, %bb.7
+  ; CHECK-PR-NEXT:   PseudoBR %bb.4
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.4.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.8(0x55555555), %bb.9(0x2aaaaaab)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x12 = ADDI $x0, 3
+  ; CHECK-PR-NEXT:   BEQ killed renamable $x10, killed renamable $x12, %bb.8
+  ; CHECK-PR-NEXT:   PseudoBR %bb.9
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.5.case0:
+  ; CHECK-PR-NEXT:   successors: %bb.10(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x10 = ADDI killed renamable $x11, 10
+  ; CHECK-PR-NEXT:   PseudoBR %bb.10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.6.case1:
+  ; CHECK-PR-NEXT:   successors: %bb.10(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x10 = ADDI killed renamable $x11, -10
+  ; CHECK-PR-NEXT:   PseudoBR %bb.10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.7.case2:
+  ; CHECK-PR-NEXT:   successors: %bb.10(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x10 = SLLI killed renamable $x11, 1
+  ; CHECK-PR-NEXT:   PseudoBR %bb.10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.8.case3:
+  ; CHECK-PR-NEXT:   successors: %bb.10(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x11
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x10 = SLLI killed renamable $x11, 1
+  ; CHECK-PR-NEXT:   PseudoBR %bb.10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.9.default:
+  ; CHECK-PR-NEXT:   successors: %bb.10(0x80000000)
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x10 = COPY $x0
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.10.exit:
+  ; CHECK-PR-NEXT:   liveins: $x10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
 entry:
   switch i64 %selector, label %default [
     i64 0, label %case0
@@ -351,65 +1075,104 @@ exit:
 }
 
 ; Test with loop with multiple exits
-; CHECK-LABEL: name: test_loop_multiple_exits
-; CHECK: bb.0.entry:
-; CHECK:   liveins: $x10, $x11, $x12
-; CHECK:   %10:gpr = COPY killed %11
-
-; CHECK: bb.3.loop_continue:
-; CHECK:   %4:gpr = ADD killed %3, %9
-; CHECK:   %5:gpr = ADDI killed %2, 1
-; CHECK:   %6:gpr = ADD killed %1, %0
-; CHECK:   PseudoBR %bb.1
-
-; CHECK: bb.4.exit1:
-; CHECK:   $x10 = COPY killed %3
-; CHECK:   PseudoRET implicit $x10
-
-; CHECK: bb.5.exit2:
-; CHECK:   $x10 = COPY killed %1
-; CHECK:   PseudoRET implicit $x10
-
-; CHECK-PR-LABEL: test_loop_multiple_exits
-; CHECK-PR:  bb.0.entry:
-; CHECK-PR:    successors:
-; CHECK-PR:    liveins: $x10, $x11, $x12
-; CHECK-PR:    renamable $x13 = COPY killed $x10
-; CHECK-PR:    renamable $x10 = COPY $x0
-; CHECK-PR:    renamable $x15 = COPY $x0
-; CHECK-PR:    renamable $x14 = COPY killed $x0
-; CHECK-PR:    renamable $x16 = SLLI renamable $x12, 1
-
-; CHECK-PR:  bb.1.loop:
-; CHECK-PR:    successors:
-; CHECK-PR:    liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16
-; CHECK-PR:    BLTU renamable $x11, renamable $x14, %bb.4
-; CHECK-PR:    PseudoBR %bb.2
-
-; CHECK-PR:  bb.2.check2:
-; CHECK-PR:    successors:
-; CHECK-PR:    liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16
-; CHECK-PR:    BLTU renamable $x13, renamable $x15, %bb.5
-; CHECK-PR:    PseudoBR %bb.3
-
-; CHECK-PR:  bb.3.loop_continue:
-; CHECK-PR:    successors:
-; CHECK-PR:    liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16
-; CHECK-PR:    renamable $x14 = ADD killed renamable $x14, renamable $x12
-; CHECK-PR:    renamable $x15 = ADDI killed renamable $x15, 1
-; CHECK-PR:    renamable $x10 = ADD killed renamable $x10, renamable $x16
-; CHECK-PR:    PseudoBR %bb.1
-
-; CHECK-PR:  bb.4.exit1:
-; CHECK-PR:    liveins: $x14
-; CHECK-PR:    $x10 = COPY killed renamable $x14
-; CHECK-PR:    PseudoRET implicit killed $x10
-
-; CHECK-PR:  bb.5.exit2:
-; CHECK-PR:    liveins: $x10
-; CHECK-PR:    PseudoRET implicit killed $x10
+
+
+
+
+
+
+
+
+
 
 define i64 @test_loop_multiple_exits(i64 %n, i64 %threshold, i64 %increment) {
+  ; CHECK-LABEL: name: test_loop_multiple_exits
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[SLLI:%[0-9]+]]:gpr = SLLI [[COPY]], 1
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY $x0
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:gpr = COPY [[COPY3]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.4(0x04000000), %bb.2(0x7c000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY4]], %bb.0, %6, %bb.3
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY4]], %bb.0, %5, %bb.3
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[COPY4]], %bb.0, %4, %bb.3
+  ; CHECK-NEXT:   BLTU [[COPY1]], [[PHI2]], %bb.4
+  ; CHECK-NEXT:   PseudoBR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.check2:
+  ; CHECK-NEXT:   successors: %bb.5(0x04000000), %bb.3(0x7c000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   BLTU [[COPY2]], [[PHI1]], %bb.5
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.loop_continue:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[PHI2]], [[COPY]]
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI1]], 1
+  ; CHECK-NEXT:   [[ADD1:%[0-9]+]]:gpr = ADD [[PHI]], [[SLLI]]
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.exit1:
+  ; CHECK-NEXT:   $x10 = COPY [[PHI2]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.exit2:
+  ; CHECK-NEXT:   $x10 = COPY [[PHI]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  ;
+  ; CHECK-PR-LABEL: name: test_loop_multiple_exits
+  ; CHECK-PR: bb.0.entry:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x13 = COPY $x10
+  ; CHECK-PR-NEXT:   renamable $x10 = COPY $x0
+  ; CHECK-PR-NEXT:   renamable $x15 = COPY $x0
+  ; CHECK-PR-NEXT:   renamable $x14 = COPY $x0
+  ; CHECK-PR-NEXT:   renamable $x16 = SLLI renamable $x12, 1
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.1.loop:
+  ; CHECK-PR-NEXT:   successors: %bb.4(0x04000000), %bb.2(0x7c000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   BLTU renamable $x11, renamable $x14, %bb.4
+  ; CHECK-PR-NEXT:   PseudoBR %bb.2
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.2.check2:
+  ; CHECK-PR-NEXT:   successors: %bb.5(0x04000000), %bb.3(0x7c000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   BLTU renamable $x13, renamable $x15, %bb.5
+  ; CHECK-PR-NEXT:   PseudoBR %bb.3
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.3.loop_continue:
+  ; CHECK-PR-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-PR-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   renamable $x14 = ADD killed renamable $x14, renamable $x12
+  ; CHECK-PR-NEXT:   renamable $x15 = ADDI killed renamable $x15, 1
+  ; CHECK-PR-NEXT:   renamable $x10 = ADD killed renamable $x10, renamable $x16
+  ; CHECK-PR-NEXT:   PseudoBR %bb.1
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.4.exit1:
+  ; CHECK-PR-NEXT:   liveins: $x14
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   $x10 = COPY killed renamable $x14
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT: bb.5.exit2:
+  ; CHECK-PR-NEXT:   liveins: $x10
+  ; CHECK-PR-NEXT: {{  $}}
+  ; CHECK-PR-NEXT:   PseudoRET implicit $x10
 entry:
   br label %loop
 
@@ -435,4 +1198,4 @@ exit1:
 exit2:
   %final = mul i64 %sum, 2
   ret i64 %final
-}
\ No newline at end of file
+}
diff --git a/llvm/test/CodeGen/RISCV/live-variables-mbb-liveness-crash.ll b/llvm/test/CodeGen/RISCV/live-variables-mbb-liveness-crash.ll
index 85e016445b368..ce2668fc1e63e 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-mbb-liveness-crash.ll
+++ b/llvm/test/CodeGen/RISCV/live-variables-mbb-liveness-crash.ll
@@ -1,27 +1,8 @@
-; RUN: llc -mtriple=riscv64 -mattr=+rva22u64 -riscv-enable-live-variables -stop-after=riscv-live-variables,1 < %s
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+; RUN: llc -mtriple=riscv64 -mattr=+rva22u64 -riscv-enable-live-variables -stop-after=sparse-live-variables,1 < %s
 target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
 target triple = "riscv64-unknown-linux-gnu"
 
-; CHECK:body:             |
-; CHECK:  bb.0.bb:
-; CHECK:    successors: %bb.1(0x00000000), %bb.2(0x80000000)
-; CHECK:    EH_LABEL <mcsymbol >
-; CHECK:    ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit killed $x2
-; CHECK:    $x10 = COPY $x0
-; CHECK:    $x11 = COPY $x0
-; CHECK:    $x12 = COPY $x0
-; CHECK:    PseudoCALL target-flags(riscv-call) @baz, csr_ilp32d_lp64d, implicit-def dead $x1, implicit killed $x10, implicit killed $x11, implicit killed $x12, implicit-def $x2
-; CHECK:    ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit killed $x2
-; CHECK:    EH_LABEL <mcsymbol >
-; CHECK:    PseudoBR %bb.1
-; CHECK:  bb.1.bb1:
-; CHECK:    successors:
-; CHECK:  bb.2.bb2 (landing-pad):
-; CHECK:    EH_LABEL <mcsymbol >
-; CHECK:    ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit killed $x2
-; CHECK:    $x10 = COPY killed $x0
-; CHECK:    PseudoCALL target-flags(riscv-call) @_Unwind_Resume, csr_ilp32d_lp64d, implicit-def dead $x1, implicit killed $x10, implicit-def $x2
-; CHECK:    ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit killed $x2
 
 define i1 @widget() personality ptr null {
 bb:
diff --git a/llvm/test/CodeGen/RISCV/live-variables-pre-regalloc.ll b/llvm/test/CodeGen/RISCV/live-variables-pre-regalloc.ll
index bed71de0d3337..31f83f69a545c 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-pre-regalloc.ll
+++ b/llvm/test/CodeGen/RISCV/live-variables-pre-regalloc.ll
@@ -1,31 +1,83 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 ; RUN: llc -mtriple riscv64 -mattr=+d -riscv-enable-live-variables \
-; RUN: --stop-after=riscv-live-variables -riscv-liveness-update-kills < %s | FileCheck %s
-
-; RUN: llc -mtriple riscv64 -mattr=+d -riscv-enable-live-variables \
-; RUN: -riscv-liveness-update-kills < %s | FileCheck --check-prefix=CHECK-LICM %s
+; RUN: --stop-after=sparse-live-variables < %s | FileCheck %s
 
 ; Issue: #166141 Pessimistic MachineLICM due to missing liveness info.
 
 ; Check that live variable analysis correctly marks %41 as kill
-; CHECK:  bb.2.if:
-; CHECK:    successors: %bb.3(0x80000000)
 ;
-; CHECK:    %40:gpr = LUI target-flags(riscv-hi) %const.0
-; CHECK:    %41:fpr64 = FLD killed %40, target-flags(riscv-lo) %const.0 :: (load (s64) from constant-pool)
-; CHECK:    %42:fpr64 = nofpexcept FMUL_D killed %2, killed %41, 7, implicit $frm
-; CHECK:    FSD killed %42, %1, 0 :: (store (s64) into %ir.lsr.iv1)
 
 ; Check that the loop invariant `fld` is hoisted out of the loop.
-; CHECK-LICM: # %bb.0:
-; CHECK-LICM:        lui     a1, %hi(.LCPI0_0)
-; CHECK-LICM:        fld     fa5, %lo(.LCPI0_0)(a1)
-; CHECK-LICM:        lui     a1, 2
-; CHECK-LICM:        add     a1, a0, a1
-; CHECK-LICM:        fmv.d.x fa4, zero
-; CHECK-LICM:        j       .LBB0_2
-; CHECK-LICM: .LBB0_1:
 
 define void @f(ptr %p) {
+  ; CHECK-LABEL: name: f
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[LUI:%[0-9]+]]:gpr = LUI 2
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[COPY]], killed [[LUI]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.2(0x50000000), %bb.3(0x30000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY]], %bb.0, %3, %bb.3
+  ; CHECK-NEXT:   [[FLD:%[0-9]+]]:fpr64 = FLD [[PHI]], 0 :: (load (s64) from %ir.lsr.iv1)
+  ; CHECK-NEXT:   [[FMUL_D:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FLD]], [[FLD]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D1:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D]], [[FMUL_D]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D2:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D1]], [[FMUL_D1]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D3:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D2]], [[FMUL_D2]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D4:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D3]], [[FMUL_D3]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D5:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D4]], [[FMUL_D4]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D6:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D5]], [[FMUL_D5]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D7:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D6]], [[FMUL_D6]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D8:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D7]], [[FMUL_D7]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D9:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D8]], [[FMUL_D8]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D10:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D9]], [[FMUL_D9]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D11:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D10]], [[FMUL_D10]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D12:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D11]], [[FMUL_D11]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D13:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D12]], [[FMUL_D12]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D14:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D13]], [[FMUL_D13]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D15:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D14]], [[FMUL_D14]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D16:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D15]], [[FMUL_D15]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D17:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D16]], [[FMUL_D16]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D18:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D17]], [[FMUL_D17]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D19:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D18]], [[FMUL_D18]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D20:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D19]], [[FMUL_D19]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D21:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D20]], [[FMUL_D20]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D22:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D21]], [[FMUL_D21]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D23:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D22]], [[FMUL_D22]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D24:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D23]], [[FMUL_D23]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D25:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D24]], [[FMUL_D24]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D26:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D25]], [[FMUL_D25]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D27:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D26]], [[FMUL_D26]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D28:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D27]], [[FMUL_D27]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D29:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D28]], [[FMUL_D28]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D30:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D29]], [[FMUL_D29]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMUL_D31:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D30]], [[FMUL_D30]], 7, implicit $frm
+  ; CHECK-NEXT:   [[FMV_D_X:%[0-9]+]]:fpr64 = FMV_D_X $x0
+  ; CHECK-NEXT:   [[FEQ_D:%[0-9]+]]:gpr = nofpexcept FEQ_D [[FMUL_D31]], killed [[FMV_D_X]]
+  ; CHECK-NEXT:   BNE killed [[FEQ_D]], $x0, %bb.3
+  ; CHECK-NEXT:   PseudoBR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.if:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[LUI1:%[0-9]+]]:gpr = LUI target-flags(riscv-hi) %const.0
+  ; CHECK-NEXT:   [[FLD1:%[0-9]+]]:fpr64 = FLD killed [[LUI1]], target-flags(riscv-lo) %const.0 :: (load (s64) from constant-pool)
+  ; CHECK-NEXT:   [[FMUL_D32:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[FMUL_D31]], killed [[FLD1]], 7, implicit $frm
+  ; CHECK-NEXT:   FSD killed [[FMUL_D32]], [[PHI]], 0 :: (store (s64) into %ir.lsr.iv1)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.latch:
+  ; CHECK-NEXT:   successors: %bb.4(0x04000000), %bb.1(0x7c000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI]], 8
+  ; CHECK-NEXT:   BNE [[ADDI]], [[ADD]], %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.exit:
+  ; CHECK-NEXT:   PseudoRET
 entry:
   br label %loop
 
diff --git a/llvm/test/CodeGen/RISCV/live-variables-rv64.ll b/llvm/test/CodeGen/RISCV/live-variables-rv64.ll
index 440337df37f29..4ab74a47dd429 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-rv64.ll
+++ b/llvm/test/CodeGen/RISCV/live-variables-rv64.ll
@@ -1,39 +1,42 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 ; RUN: llc -mtriple=riscv64 -riscv-enable-live-variables -verify-machineinstrs \
-; RUN: -riscv-enable-live-variables -riscv-liveness-update-kills -stop-after=riscv-live-variables \
+; RUN: -riscv-enable-live-variables -stop-after=sparse-live-variables \
 ; RUN: -o - %s | FileCheck %s
 
 ; Test live variable analysis for RV64-specific scenarios
 ; This includes 64-bit operations, wide registers, and RV64-specific instructions
 
-; CHECK:  test_64bit_ops
-; CHECK:  bb.0.entry:
-; CHECK:    liveins: $x10, $x11
 ;
-; CHECK:    %1:gpr = COPY $x11
-; CHECK:    %0:gpr = COPY $x10
-; CHECK:    %2:gpr = SLLI killed %0, 32
-; CHECK:    %3:gpr = OR killed %2, killed %1
-; CHECK:    $x10 = COPY killed %3
-; CHECK:    PseudoRET implicit $x10
 
 define i64 @test_64bit_ops(i64 %a, i64 %b) {
+  ; CHECK-LABEL: name: test_64bit_ops
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   liveins: $x10, $x11
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[SLLI:%[0-9]+]]:gpr = SLLI [[COPY1]], 32
+  ; CHECK-NEXT:   [[OR:%[0-9]+]]:gpr = OR killed [[SLLI]], [[COPY]]
+  ; CHECK-NEXT:   $x10 = COPY [[OR]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
 entry:
   %shl = shl i64 %a, 32
   %or = or i64 %shl, %b
   ret i64 %or
 }
 
-; CHECK:  test_word_ops
-; CHECK:  bb.0.entry:
-; CHECK:    liveins: $x10, $x11
 ;
-; CHECK:    %1:gpr = COPY $x11
-; CHECK:    %0:gpr = COPY $x10
-; CHECK:    %2:gpr = ADDW killed %0, killed %1
-; CHECK:    $x10 = COPY killed %2
-; CHECK:    PseudoRET implicit $x10
 
 define i64 @test_word_ops(i64 %a, i64 %b) {
+  ; CHECK-LABEL: name: test_word_ops
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   liveins: $x10, $x11
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[ADDW:%[0-9]+]]:gpr = ADDW [[COPY1]], [[COPY]]
+  ; CHECK-NEXT:   $x10 = COPY [[ADDW]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
 entry:
   %trunc_a = trunc i64 %a to i32
   %trunc_b = trunc i64 %b to i32
@@ -42,23 +45,24 @@ entry:
   ret i64 %ext
 }
 
-; CHECK:  test_mixed_width
-; CHECK:  bb.0.entry:
-; CHECK:    liveins: $x10, $x11
 ;
-; CHECK:    %1:gpr = COPY $x11
-; CHECK:    %0:gpr = COPY $x10
-; CHECK:    ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:    $x10 = COPY killed %0
-; CHECK:    $x11 = COPY killed %1
-; CHECK:    PseudoCALL target-flags(riscv-call) &__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
-; CHECK:    ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:    %2:gpr = COPY $x10
-; CHECK:    %3:gpr = ADDIW killed %2, 0
-; CHECK:    $x10 = COPY killed %3
-; CHECK:    PseudoRET implicit $x10
 
 define i64 @test_mixed_width(i64 %a, i32 %b) {
+  ; CHECK-LABEL: name: test_mixed_width
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   liveins: $x10, $x11
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   $x10 = COPY [[COPY1]]
+  ; CHECK-NEXT:   $x11 = COPY [[COPY]]
+  ; CHECK-NEXT:   PseudoCALL target-flags(riscv-call) &__muldi3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[ADDIW:%[0-9]+]]:gpr = ADDIW [[COPY2]], 0
+  ; CHECK-NEXT:   $x10 = COPY [[ADDIW]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
 entry:
   %ext_b = sext i32 %b to i64
   %mul = mul i64 %a, %ext_b
@@ -67,48 +71,54 @@ entry:
   ret i64 %final
 }
 
-; CHECK:  test_float_64
-; CHECK:  bb.0.entry:
-; CHECK:    successors: %bb.1(0x30000000), %bb.2(0x50000000)
-; CHECK:    liveins: $x10, $x11, $x12
 ;
-; CHECK:    %5:gpr = COPY $x12
-; CHECK:    %4:gpr = COPY $x11
-; CHECK:    %3:gpr = COPY $x10
-; CHECK:    %7:gpr = COPY killed %4
-; CHECK:    %6:gpr = COPY killed %3
-; CHECK:    BNE killed %5, $x0, %bb.2
-; CHECK:    PseudoBR %bb.1
 ;
-; CHECK:  bb.1.then:
-; CHECK:    successors: %bb.3(0x80000000)
 ;
-; CHECK:    ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:    $x10 = COPY killed %6
-; CHECK:    $x11 = COPY killed %7
-; CHECK:    PseudoCALL target-flags(riscv-call) &__adddf3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
-; CHECK:    ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:    %9:gpr = COPY $x10
-; CHECK:    %0:gpr = COPY killed %9
-; CHECK:    PseudoBR %bb.3
 ;
-; CHECK:  bb.2.else:
-; CHECK:    successors: %bb.3(0x80000000)
 ;
-; CHECK:    ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:    $x10 = COPY killed %6
-; CHECK:    $x11 = COPY killed %7
-; CHECK:    PseudoCALL target-flags(riscv-call) &__muldf3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
-; CHECK:    ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
-; CHECK:    %8:gpr = COPY $x10
-; CHECK:    %1:gpr = COPY killed %8
 ;
-; CHECK:  bb.3.end:
-; CHECK:    %2:gpr = PHI %1, %bb.2, %0, %bb.1
-; CHECK:    $x10 = COPY killed %2
-; CHECK:    PseudoRET implicit $x10
 
 define double @test_float_64(double %a, double %b, i64 %selector) {
+  ; CHECK-LABEL: name: test_float_64
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x30000000), %bb.2(0x50000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY [[COPY1]]
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:gpr = COPY [[COPY2]]
+  ; CHECK-NEXT:   BNE [[COPY]], $x0, %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.then:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   $x10 = COPY [[COPY4]]
+  ; CHECK-NEXT:   $x11 = COPY [[COPY3]]
+  ; CHECK-NEXT:   PseudoCALL target-flags(riscv-call) &__adddf3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY6:%[0-9]+]]:gpr = COPY [[COPY5]]
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.else:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   $x10 = COPY [[COPY4]]
+  ; CHECK-NEXT:   $x11 = COPY [[COPY3]]
+  ; CHECK-NEXT:   PseudoCALL target-flags(riscv-call) &__muldf3, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit $x11, implicit-def $x2, implicit-def $x10
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
+  ; CHECK-NEXT:   [[COPY7:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY8:%[0-9]+]]:gpr = COPY [[COPY7]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.end:
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY8]], %bb.2, [[COPY6]], %bb.1
+  ; CHECK-NEXT:   $x10 = COPY [[PHI]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
 entry:
   %cmp = icmp eq i64 %selector, 0
   br i1 %cmp, label %then, label %else
@@ -124,4 +134,4 @@ else:
 end:
   %result = phi double [ %add, %then ], [ %mul, %else ]
   ret double %result
-}
\ No newline at end of file
+}
diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
index 709017380fa4e..421c735b9fdff 100644
--- a/llvm/unittests/CodeGen/CMakeLists.txt
+++ b/llvm/unittests/CodeGen/CMakeLists.txt
@@ -48,6 +48,7 @@ add_llvm_unittest(CodeGenTests
   SelectionDAGAddressAnalysisTest.cpp
   SelectionDAGNodeConstructionTest.cpp
   SelectionDAGPatternMatchTest.cpp
+  SparseLiveVariablesTest.cpp
   TypeTraitsTest.cpp
   TargetOptionsTest.cpp
   TestAsmPrinter.cpp
diff --git a/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp b/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
new file mode 100644
index 0000000000000..a03c188396803
--- /dev/null
+++ b/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
@@ -0,0 +1,100 @@
+//===- SparseLiveVariablesTest.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/SparseLiveVariables.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
+#include "llvm/CodeGen/CodeGenTargetMachineImpl.h"
+#include "llvm/IR/Module.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+#include "MFCommon.inc"
+
+TEST(SparseLiveVariablesTest, APITests) {
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
+  auto MBB = MF->CreateMachineBasicBlock();
+  MF->push_back(MBB);
+
+  MCInstrDesc MCID = {100, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+
+  MCRegisterClass MRC{
+      0, 0, 0, 0, 0, 0, 0, 0, /*Allocatable=*/true, /*BaseClass=*/true};
+  TargetRegisterClass RC{&MRC, 0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0};
+  MachineRegisterInfo &MRI = MF->getRegInfo();
+
+  Register Reg0 = MRI.createVirtualRegister(&RC);
+  Register Reg1 = MRI.createVirtualRegister(&RC);
+  Register Reg2 = MRI.createVirtualRegister(&RC);
+
+  // MI1: %1 = OP %0
+  MachineInstr *MI1 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI1->addOperand(*MF, MachineOperand::CreateReg(Reg1, /*isDef*/ true));
+  MI1->addOperand(*MF, MachineOperand::CreateReg(Reg0, /*isDef*/ false));
+  MBB->insert(MBB->end(), MI1);
+
+  // MI2: %2 = OP %1
+  MachineInstr *MI2 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg2, /*isDef*/ true));
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg1, /*isDef*/ false));
+  MBB->insert(MBB->end(), MI2);
+
+  // Run SparseLiveVariables analysis
+  SparseLiveVariables LV;
+  LV.runOnMachineFunction(*MF);
+
+  // API Tests for Reg0 at MI1 (killed)
+  EXPECT_TRUE(LV.isLiveAt(Reg0, *MI1));
+  EXPECT_FALSE(LV.isLiveAfter(Reg0, *MI1));
+  EXPECT_TRUE(LV.isKillAt(Reg0, *MI1));
+
+  // API Tests for Reg1 at MI1 (defined)
+  EXPECT_FALSE(LV.isLiveAt(Reg1, *MI1));
+  EXPECT_TRUE(LV.isLiveAfter(Reg1, *MI1));
+  EXPECT_FALSE(LV.isKillAt(Reg1, *MI1));
+
+  // API Tests for Reg1 at MI2 (killed)
+  EXPECT_TRUE(LV.isLiveAt(Reg1, *MI2));
+  EXPECT_FALSE(LV.isLiveAfter(Reg1, *MI2));
+  EXPECT_TRUE(LV.isKillAt(Reg1, *MI2));
+
+  // API Tests for Reg2 at MI1 (not yet defined, not live)
+  EXPECT_FALSE(LV.isLiveAt(Reg2, *MI1));
+  EXPECT_FALSE(LV.isLiveAfter(Reg2, *MI1));
+  EXPECT_FALSE(LV.isKillAt(Reg2, *MI1));
+
+  // Block Level Sets Check
+  const SparseBitVector<> &LiveIn = LV.getLiveInSet(MBB);
+  const SparseBitVector<> &LiveOut = LV.getLiveOutSet(MBB);
+
+  // Reg0 is used before being defined -> must be LiveIn
+  EXPECT_TRUE(LiveIn.test(Reg0.id()));
+  EXPECT_FALSE(LiveIn.test(Reg1.id()));
+  EXPECT_FALSE(LiveIn.test(Reg2.id()));
+
+  // No registers are live out (MBB is the only block)
+  EXPECT_FALSE(LiveOut.test(Reg0.id()));
+  EXPECT_FALSE(LiveOut.test(Reg1.id()));
+  EXPECT_FALSE(LiveOut.test(Reg2.id()));
+}
+
+} // end namespace

>From 2cd3f4035815a38161c65b2b3671cfa2832d2587 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sat, 18 Apr 2026 14:53:21 -0700
Subject: [PATCH 24/32] Make it an analysis pass and document

---
 .../llvm/CodeGen/SparseLiveVariables.h        | 76 ++++++++++++--
 llvm/lib/CodeGen/SparseLiveVariables.cpp      | 99 +++++++++++++++----
 .../CodeGen/RISCV/live-variables-basic.mir    | 64 ++----------
 .../CodeGen/RISCV/machine-live-variables.mir  | 76 --------------
 .../CodeGen/SparseLiveVariablesTest.cpp       | 15 ++-
 5 files changed, 174 insertions(+), 156 deletions(-)
 delete mode 100644 llvm/test/CodeGen/RISCV/machine-live-variables.mir

diff --git a/llvm/include/llvm/CodeGen/SparseLiveVariables.h b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
index e39a1b2089d0f..a98fb3b53be1f 100644
--- a/llvm/include/llvm/CodeGen/SparseLiveVariables.h
+++ b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
@@ -1,11 +1,31 @@
-//===-- SparseLiveVariables.h - RISC-V Live Variable Analysis ------*- C++ -*-===//
+//===-- SparseLiveVariables.h - Sparse Live Variable Analysis ----*- C++
+//-*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-
+//
+// This file implements a sparse, target-independent liveness analysis pass.
+//
+// Design Decisions & Computational Sparsity:
+// 1. Data Structure Sparsity: Virtual registers in LLVM have very large IDs
+//    (starting at 2^30). Tracking their liveness using a dense BitVector would
+//    allocate an exorbitant amount of memory. This pass uses SparseBitVector
+//    to lazily allocate small chunks, keeping the memory footprint tiny even
+//    for sparse, high-ID virtual registers.
+//
+// 2. Computational Sparsity (Statelessness): Unlike the legacy LiveVariables
+//    pass which computes and caches full liveness intervals and records every
+//    Def/Kill point globally, this pass strictly computes only the block-level
+//    boundary conditions (LiveIn and LiveOut). Instruction-level liveness
+//    is intentionally not cached. Instead, queries are evaluated "on the fly"
+//    by walking backward from the block's LiveOut set using a LivenessTracker.
+//    This trades a small amount of compute for significant memory savings and
+//    eliminates the maintenance burden of massive state caches.
+//
+//===----------------------------------------------------------------------===//
 #ifndef LLVM_CODEGEN_SPARSELIVEVARIABLES_H
 #define LLVM_CODEGEN_SPARSELIVEVARIABLES_H
 
@@ -20,6 +40,13 @@
 
 namespace llvm {
 
+/// SparseLiveVariables - A target-independent liveness analysis pass.
+///
+/// This pass computes block-level live-in and live-out sets using a
+/// SparseBitVector representation. It is designed to be a lightweight,
+/// memory-efficient alternative to the legacy LiveVariables pass. It operates
+/// as a read-only analysis but provides mutation APIs (`updateLiveIns`,
+/// `updateKillFlags`) to explicitly update the IR state if desired.
 class SparseLiveVariables : public MachineFunctionPass {
 public:
   static char ID;
@@ -33,15 +60,26 @@ class SparseLiveVariables : public MachineFunctionPass {
 
   DenseMap<const MachineBasicBlock *, BlockInfo> BlockLiveness;
 
+  /// LivenessTracker - A utility class for backward liveness traversal.
+  ///
+  /// This class tracks the liveness state of registers as you step backward
+  /// through a MachineBasicBlock. It is initialized with the Live-Out set of
+  /// the block and updated by calling `stepBackward(MI)` on each instruction.
+  ///
+  /// Note: The SparseLiveVariables pass itself is stateless at the instruction
+  /// level. To query instruction-level liveness dynamically, you must use this
+  /// tracker or the `isLiveAt`/`isLiveAfter` methods (which internally use it).
   class LivenessTracker {
     SparseBitVector<> LiveRegs;
     const MachineRegisterInfo *MRI;
 
   public:
     bool isTrackableRegister(Register Reg) const {
-      if (Reg.isVirtual()) return true;
+      if (Reg.isVirtual())
+        return true;
       if (Reg.isPhysical()) {
-        if (MRI->isReserved(Reg)) return false;
+        if (MRI->isReserved(Reg))
+          return false;
         return true;
       }
       return false;
@@ -49,7 +87,7 @@ class SparseLiveVariables : public MachineFunctionPass {
 
     LivenessTracker(const SparseBitVector<> &LiveOut,
                     const MachineRegisterInfo *MRI)
-: LiveRegs(LiveOut), MRI(MRI) {}
+        : LiveRegs(LiveOut), MRI(MRI) {}
 
     void stepBackward(const MachineInstr &MI) {
       if (MI.isDebugInstr() || MI.isMetaInstruction())
@@ -75,34 +113,56 @@ class SparseLiveVariables : public MachineFunctionPass {
     }
 
     bool isLive(Register Reg) const {
-      if (!Reg.isValid()) return false;
+      if (!Reg.isValid())
+        return false;
       return LiveRegs.test(Reg.id());
     }
 
     const SparseBitVector<> &getLiveSet() const { return LiveRegs; }
   };
 
-
+  /// Returns the computed Live-In set for the given MachineBasicBlock.
   const SparseBitVector<> &getLiveInSet(const MachineBasicBlock *MBB) const {
     auto It = BlockLiveness.find(MBB);
     assert(It != BlockLiveness.end() && "Block not analyzed");
     return It->second.LiveIn;
   }
 
+  /// Returns the computed Live-Out set for the given MachineBasicBlock.
   const SparseBitVector<> &getLiveOutSet(const MachineBasicBlock *MBB) const {
     auto It = BlockLiveness.find(MBB);
     assert(It != BlockLiveness.end() && "Block not analyzed");
     return It->second.LiveOut;
   }
 
+  /// Returns true if Reg is live immediately AFTER the execution of MI.
+  /// Note: This performs an O(N) backward traversal from the end of the block.
   bool isLiveAfter(Register Reg, const MachineInstr &MI) const;
+
+  /// Returns true if Reg is live immediately BEFORE the execution of MI.
+  /// Note: This performs an O(N) backward traversal from the end of the block.
   bool isLiveAt(Register Reg, const MachineInstr &MI) const;
+
+  /// Returns true if Reg is killed by MI (used by MI and not live after).
+  /// Note: This performs an O(N) backward traversal from the end of the block.
   bool isKillAt(Register Reg, const MachineInstr &MI) const;
+
+  /// Validates the computed block liveness against existing MachineBasicBlock
+  /// live-ins.
   void verifyLiveness(const MachineFunction &MF) const;
 
+  /// Update the live-ins of all basic blocks in MF based on computed liveness.
+  void updateLiveIns(MachineFunction &MF) const;
+
+  /// Update the kill flags of all instructions in MF based on computed
+  /// liveness.
+  void updateKillFlags(MachineFunction &MF) const;
+
   bool runOnMachineFunction(MachineFunction &MF) override;
 
-  StringRef getPassName() const override { return "RISC-V Live Variable Analysis"; }
+  StringRef getPassName() const override {
+    return "Sparse Live Variable Analysis";
+  }
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
     AU.setPreservesAll();
diff --git a/llvm/lib/CodeGen/SparseLiveVariables.cpp b/llvm/lib/CodeGen/SparseLiveVariables.cpp
index eb1d7fcc0741d..d390cb218e6b3 100644
--- a/llvm/lib/CodeGen/SparseLiveVariables.cpp
+++ b/llvm/lib/CodeGen/SparseLiveVariables.cpp
@@ -1,15 +1,22 @@
+//===-- SparseLiveVariables.cpp - Sparse Live Variable Analysis -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
 #include "llvm/CodeGen/SparseLiveVariables.h"
-#include "llvm/InitializePasses.h"
-#include "llvm/ADT/SparseBitVector.h"
 #include "llvm/ADT/DepthFirstIterator.h"
 #include "llvm/ADT/PostOrderIterator.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/ADT/SparseBitVector.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineInstr.h"
 #include "llvm/CodeGen/MachineOperand.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/TargetRegisterInfo.h"
 #include "llvm/CodeGen/Passes.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
+#include "llvm/InitializePasses.h"
 #include "llvm/Support/Debug.h"
 
 using namespace llvm;
@@ -17,7 +24,8 @@ using namespace llvm;
 #define DEBUG_TYPE "sparse-live-variables"
 
 char SparseLiveVariables::ID = 0;
-INITIALIZE_PASS(SparseLiveVariables, DEBUG_TYPE, "Sparse Live Variable Analysis", false, false)
+INITIALIZE_PASS(SparseLiveVariables, DEBUG_TYPE,
+                "Sparse Live Variable Analysis", false, false)
 
 bool SparseLiveVariables::runOnMachineFunction(MachineFunction &MF) {
   if (skipFunction(MF.getFunction()) || MF.empty())
@@ -25,7 +33,7 @@ bool SparseLiveVariables::runOnMachineFunction(MachineFunction &MF) {
 
   MRI = &MF.getRegInfo();
   TRI = MF.getSubtarget().getRegisterInfo();
-  
+
   BlockLiveness.clear();
 
   SmallPtrSet<MachineBasicBlock *, 16> Reachable;
@@ -36,7 +44,8 @@ bool SparseLiveVariables::runOnMachineFunction(MachineFunction &MF) {
   while (Changed) {
     Changed = false;
     for (MachineBasicBlock *MBB : llvm::post_order(&MF)) {
-      if (!Reachable.count(MBB)) continue;
+      if (!Reachable.count(MBB))
+        continue;
 
       SparseBitVector<> OldLiveIn = BlockLiveness[MBB].LiveIn;
       SparseBitVector<> OldLiveOut = BlockLiveness[MBB].LiveOut;
@@ -68,7 +77,7 @@ bool SparseLiveVariables::runOnMachineFunction(MachineFunction &MF) {
         for (const MachineOperand &MO : MI.operands()) {
           if (MO.isReg() && MO.getReg().isValid() && MO.getReg().isVirtual()) {
             Register Reg = MO.getReg();
-            dbgs() << "    Reg " << printReg(Reg, TRI) 
+            dbgs() << "    Reg " << printReg(Reg, TRI)
                    << " isLiveAfter: " << isLiveAfter(Reg, MI)
                    << ", isLiveAt: " << isLiveAt(Reg, MI)
                    << ", isKillAt: " << isKillAt(Reg, MI) << "\n";
@@ -81,13 +90,12 @@ bool SparseLiveVariables::runOnMachineFunction(MachineFunction &MF) {
   return false;
 }
 
-
-
-
-bool SparseLiveVariables::isLiveAfter(Register Reg, const MachineInstr &MI) const {
+bool SparseLiveVariables::isLiveAfter(Register Reg,
+                                      const MachineInstr &MI) const {
   const MachineBasicBlock *MBB = MI.getParent();
   auto It = BlockLiveness.find(MBB);
-  if (It == BlockLiveness.end()) return false;
+  if (It == BlockLiveness.end())
+    return false;
 
   LivenessTracker Tracker(It->second.LiveOut, MRI);
   for (const MachineInstr &I : llvm::reverse(*MBB)) {
@@ -101,7 +109,8 @@ bool SparseLiveVariables::isLiveAfter(Register Reg, const MachineInstr &MI) cons
 bool SparseLiveVariables::isLiveAt(Register Reg, const MachineInstr &MI) const {
   const MachineBasicBlock *MBB = MI.getParent();
   auto It = BlockLiveness.find(MBB);
-  if (It == BlockLiveness.end()) return false;
+  if (It == BlockLiveness.end())
+    return false;
 
   LivenessTracker Tracker(It->second.LiveOut, MRI);
   for (const MachineInstr &I : llvm::reverse(*MBB)) {
@@ -115,7 +124,8 @@ bool SparseLiveVariables::isLiveAt(Register Reg, const MachineInstr &MI) const {
 bool SparseLiveVariables::isKillAt(Register Reg, const MachineInstr &MI) const {
   const MachineBasicBlock *MBB = MI.getParent();
   auto It = BlockLiveness.find(MBB);
-  if (It == BlockLiveness.end()) return false;
+  if (It == BlockLiveness.end())
+    return false;
 
   LivenessTracker Tracker(It->second.LiveOut, MRI);
   for (const MachineInstr &I : llvm::reverse(*MBB)) {
@@ -133,16 +143,71 @@ bool SparseLiveVariables::isKillAt(Register Reg, const MachineInstr &MI) const {
 void SparseLiveVariables::verifyLiveness(const MachineFunction &MF) const {
   for (const MachineBasicBlock &MBB : MF) {
     auto It = BlockLiveness.find(&MBB);
-    if (It == BlockLiveness.end()) continue;
+    if (It == BlockLiveness.end())
+      continue;
 
     const SparseBitVector<> &LiveIn = It->second.LiveIn;
     for (const auto &LI : MBB.liveins()) {
       if (!LiveIn.test(LI.PhysReg.id())) {
-        LLVM_DEBUG(dbgs() << "Warning: Live-in register " << printReg(LI.PhysReg, TRI)
+        LLVM_DEBUG(dbgs() << "Warning: Live-in register "
+                          << printReg(LI.PhysReg, TRI)
                           << " missing from computed live-in set of block "
                           << printMBBReference(MBB) << "\n");
       }
     }
   }
 }
+void SparseLiveVariables::updateLiveIns(MachineFunction &MF) const {
+  for (MachineBasicBlock &MBB : MF) {
+    auto It = BlockLiveness.find(&MBB);
+    if (It == BlockLiveness.end())
+      continue;
+
+    MBB.clearLiveIns();
+    const SparseBitVector<> &LiveIn = It->second.LiveIn;
+    for (unsigned RegID : LiveIn) {
+      Register Reg(RegID);
+      // MBB.addLiveIn only takes physical registers.
+      if (Reg.isPhysical())
+        MBB.addLiveIn(Reg);
+    }
+    MBB.sortUniqueLiveIns();
+  }
+}
+
+void SparseLiveVariables::updateKillFlags(MachineFunction &MF) const {
+  for (MachineBasicBlock &MBB : MF) {
+    auto It = BlockLiveness.find(&MBB);
+    if (It == BlockLiveness.end())
+      continue;
+
+    LivenessTracker Tracker(It->second.LiveOut, MRI);
+    for (MachineInstr &MI : llvm::reverse(MBB)) {
+      if (MI.isDebugInstr() || MI.isMetaInstruction())
+        continue;
+
+      // Check uses and update their kill flags based on whether they are live
+      // BEFORE stepBackward. (Tracker currently represents the liveness state
+      // AFTER this instruction).
+      for (MachineOperand &MO : MI.operands()) {
+        if (!MO.isReg() || !MO.isUse())
+          continue;
+        Register Reg = MO.getReg();
+        if (!Tracker.isTrackableRegister(Reg))
+          continue;
+
+        if (!Tracker.isLive(Reg)) {
+          // If the register is not live after this instruction, it is a kill.
+          MO.setIsKill(true);
+        } else {
+          // Otherwise, clear the kill flag if it was set incorrectly.
+          MO.setIsKill(false);
+        }
+      }
+
+      Tracker.stepBackward(MI);
+    }
+  }
+}
+
 char &llvm::SparseLiveVariablesID = SparseLiveVariables::ID;
diff --git a/llvm/test/CodeGen/RISCV/live-variables-basic.mir b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
index f8353e10c27b1..bcaa7f32a541b 100644
--- a/llvm/test/CodeGen/RISCV/live-variables-basic.mir
+++ b/llvm/test/CodeGen/RISCV/live-variables-basic.mir
@@ -5,50 +5,6 @@
 
 # REQUIRES: asserts
 
---- |
-  define i64 @test_simple_add(i64 %a, i64 %b) {
-  entry:
-    %sum = add i64 %a, %b
-    ret i64 %sum
-  }
-
-  define i64 @test_if_then_else(i64 %a, i64 %b) {
-  entry:
-    %cmp = icmp sgt i64 %a, %b
-    br i1 %cmp, label %then, label %else
-
-  then:
-    %mul = mul i64 %a, %b
-    br label %end
-
-  else:
-    %sub = sub i64 %a, %b
-    br label %end
-
-  end:
-    %result = phi i64 [ %mul, %then ], [ %sub, %else ]
-    ret i64 %result
-  }
-
-  define i64 @test_multiple_uses(i64 %a, i64 %b, i64 %c) {
-  entry:
-    %t1 = add i64 %a, %b
-    %t2 = mul i64 %t1, %c
-    %t3 = sub i64 %t2, %a
-    %t4 = add i64 %t3, %b
-    ret i64 %t4
-  }
-
-  define i64 @test_gen_kill(i64 %a, i64 %b, i64 %c) {
-  entry:
-    %t1 = add i64 %a, %b
-    %t2 = mul i64 %t1, %c
-    %t3 = sub i64 %t2, %a
-    %t4 = add i64 %t3, %b
-    ret i64 %t4
-  }
-
-...
 ---
 name:            test_simple_add
 alignment:       4
@@ -61,7 +17,7 @@ liveins:
   - { reg: '$x10', virtual-reg: '%0' }
   - { reg: '$x11', virtual-reg: '%1' }
 body:             |
-  bb.0.entry:
+  bb.0:
     liveins: $x10, $x11
     ; Test that %0 and %1 are live-in, used once, and %2 is defined
 
@@ -94,7 +50,7 @@ liveins:
   - { reg: '$x11', virtual-reg: '%1' }
 body:             |
   ; CHECK-LABEL: name: test_if_then_else
-  ; CHECK: bb.0.entry:
+  ; CHECK: bb.0:
   ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.1(0x40000000)
   ; CHECK-NEXT:   liveins: $x10, $x11
   ; CHECK-NEXT: {{  $}}
@@ -103,23 +59,23 @@ body:             |
   ; CHECK-NEXT:   [[SLT:%[0-9]+]]:gpr = SLT [[COPY1]], [[COPY]]
   ; CHECK-NEXT:   BEQ [[SLT]], $x0, %bb.2
   ; CHECK-NEXT: {{  $}}
-  ; CHECK-NEXT: bb.1.then:
+  ; CHECK-NEXT: bb.1:
   ; CHECK-NEXT:   successors: %bb.3(0x80000000)
   ; CHECK-NEXT: {{  $}}
   ; CHECK-NEXT:   [[MUL:%[0-9]+]]:gpr = MUL [[COPY]], [[COPY1]]
   ; CHECK-NEXT:   PseudoBR %bb.3
   ; CHECK-NEXT: {{  $}}
-  ; CHECK-NEXT: bb.2.else:
+  ; CHECK-NEXT: bb.2:
   ; CHECK-NEXT:   successors: %bb.3(0x80000000)
   ; CHECK-NEXT: {{  $}}
   ; CHECK-NEXT:   [[SUB:%[0-9]+]]:gpr = SUB [[COPY]], [[COPY1]]
   ; CHECK-NEXT:   PseudoBR %bb.3
   ; CHECK-NEXT: {{  $}}
-  ; CHECK-NEXT: bb.3.end:
+  ; CHECK-NEXT: bb.3:
   ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[MUL]], %bb.1, [[SUB]], %bb.2
   ; CHECK-NEXT:   $x10 = COPY [[PHI]]
   ; CHECK-NEXT:   PseudoRET implicit $x10
-  bb.0.entry:
+  bb.0:
     liveins: $x10, $x11
     ; Test that %0 and %1 are live across multiple blocks
 
@@ -128,17 +84,17 @@ body:             |
     %2:gpr = SLT %1, %0
     BEQ %2, $x0, %bb.2
 
-  bb.1.then:
+  bb.1:
     ; %0 and %1 should be live-in here
     %3:gpr = MUL %0, %1
     PseudoBR %bb.3
 
-  bb.2.else:
+  bb.2:
     ; %0 and %1 should be live-in here
     %4:gpr = SUB %0, %1
     PseudoBR %bb.3
 
-  bb.3.end:
+  bb.3:
     ; Either %3 or %4 should be live-in (phi sources)
     %5:gpr = PHI %3, %bb.1, %4, %bb.2
     $x10 = COPY %5
@@ -161,7 +117,7 @@ liveins:
   - { reg: '$x11', virtual-reg: '%1' }
   - { reg: '$x12', virtual-reg: '%2' }
 body:             |
-  bb.0.entry:
+  bb.0:
     liveins: $x10, $x11, $x12
     ; Test that variables with multiple uses have correct liveness ranges
 
diff --git a/llvm/test/CodeGen/RISCV/machine-live-variables.mir b/llvm/test/CodeGen/RISCV/machine-live-variables.mir
deleted file mode 100644
index 964324323bf06..0000000000000
--- a/llvm/test/CodeGen/RISCV/machine-live-variables.mir
+++ /dev/null
@@ -1,76 +0,0 @@
-# RUN: llc -x mir -mtriple=riscv64 -verify-machineinstrs -riscv-enable-live-variables -debug < %s 2>&1 \
-# RUN: | FileCheck %s
-
-# REQUIRES: asserts
-
-# CHECK: Block: (Number: 0)
-# CHECK:   Live-In:  { $x11 $x12 $x13 $x14 $x15 $x16 $x17 $x11_h $x12_h $x13_h $x14_h $x15_h $x16_h $x17_h $x11_w $x12_w $x13_w $x14_w $x15_w $x16_w $x17_w }
-# CHECK:   Live-Out: { }
-# CHECK:   Use:      { $x11 $x12 $x13 $x14 $x15 $x16 $x17 $x11_h $x12_h $x13_h $x14_h $x15_h $x16_h $x17_h $x11_w $x12_w $x13_w $x14_w $x15_w $x16_w $x17_w }
-# CHECK:   Def:      { $x10 $x11 $x12 $x10_h $x11_h $x12_h $x10_w $x11_w $x12_w }
-
---- |
-
-  source_filename = "liveness-varargs.ll"
-  target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
-  target triple = "riscv64"
-
-  declare void @notdead(ptr)
-
-  define i32 @va1(ptr %fmt, ...) {
-    %va = alloca ptr, align 8
-    call void @llvm.va_start.p0(ptr %va)
-    %argp.cur = load ptr, ptr %va, align 4
-    %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4
-    store ptr %argp.next, ptr %va, align 4
-    %1 = load i32, ptr %argp.cur, align 4
-    call void @llvm.va_end.p0(ptr %va)
-    ret i32 %1
-  }
-
-  declare void @llvm.va_start.p0(ptr) #1
-
-  declare void @llvm.va_end.p0(ptr) #1
-
-  declare void @llvm.va_copy.p0(ptr, ptr) #1
-
-  attributes #0 = { nounwind }
-  attributes #1 = { nocallback nofree nosync nounwind willreturn }
-...
-
----
-name: va1
-tracksRegLiveness: true
-noVRegs: false
-fixedStack:
-  - { id: 0, offset: 8, size: 8, alignment: 8, isImmutable: false }
-  - { id: 1, offset: 56, size: 56, alignment: 8, isImmutable: true }
-  - { id: 2, offset: 64, size: 8, alignment: 16, isImmutable: true }
-stack:
-  - { id: 0, name: va, size: 2, alignment: 2, stack-id: default }
-
-body: |
-  bb.0:
-    liveins: $x11, $x12, $x13, $x14, $x15, $x16, $x17
-    SD killed renamable $x11, %fixed-stack.1, 0 :: (store (s64) into %fixed-stack.1)
-    SD killed renamable $x12, %fixed-stack.1, 8 :: (store (s64) into %fixed-stack.1 + 8)
-    SD killed renamable $x13, %fixed-stack.1, 16 :: (store (s64) into %fixed-stack.1 + 16)
-    SD killed renamable $x14, %fixed-stack.1, 24 :: (store (s64) into %fixed-stack.1 + 24)
-    renamable $x10 = ADDI %stack.0.va, 0
-    renamable $x11 = ADDI %fixed-stack.1, 0
-    SD killed renamable $x11, %stack.0.va, 0 :: (store (s64) into %ir.va)
-    renamable $x10 = LW killed renamable $x10, 4 :: (dereferenceable load (s32) from %ir.va + 4)
-    renamable $x11 = LWU %stack.0.va, 0 :: (dereferenceable load (s32) from %ir.va)
-    SD killed renamable $x15, %fixed-stack.1, 32 :: (store (s64) into %fixed-stack.1 + 32)
-    SD killed renamable $x16, %fixed-stack.1, 40 :: (store (s64) into %fixed-stack.1 + 40)
-    SD killed renamable $x17, %fixed-stack.1, 48 :: (store (s64) into %fixed-stack.1 + 48)
-    renamable $x10 = SLLI killed renamable $x10, 32
-    renamable $x10 = OR killed renamable $x10, killed renamable $x11
-    renamable $x11 = nuw nusw inbounds ADDI renamable $x10, 4
-    renamable $x12 = SRLI renamable $x11, 32
-    SW killed renamable $x11, %stack.0.va, 0 :: (store (s32) into %ir.va)
-    SW killed renamable $x12, %stack.0.va, 4 :: (store (s32) into %ir.va + 4)
-    renamable $x10 = LW killed renamable $x10, 0 :: (load (s32) from %ir.argp.cur)
-    PseudoRET implicit $x10
-
-...
diff --git a/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp b/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
index a03c188396803..e62a4af2b14a2 100644
--- a/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
+++ b/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
@@ -7,13 +7,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/CodeGen/SparseLiveVariables.h"
+#include "llvm/CodeGen/CodeGenTargetMachineImpl.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstr.h"
 #include "llvm/CodeGen/MachineOperand.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
-#include "llvm/CodeGen/CodeGenTargetMachineImpl.h"
 #include "llvm/IR/Module.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCSymbol.h"
@@ -95,6 +95,19 @@ TEST(SparseLiveVariablesTest, APITests) {
   EXPECT_FALSE(LiveOut.test(Reg0.id()));
   EXPECT_FALSE(LiveOut.test(Reg1.id()));
   EXPECT_FALSE(LiveOut.test(Reg2.id()));
+
+  // Test the mutation APIs
+  LV.updateKillFlags(*MF);
+
+  // Reg0 should have a kill flag on MI1
+  EXPECT_TRUE(MI1->getOperand(1).isKill());
+
+  // Reg1 should have a kill flag on MI2
+  EXPECT_TRUE(MI2->getOperand(1).isKill());
+
+  // Test updateLiveIns (won't add virtual registers, but shouldn't crash)
+  LV.updateLiveIns(*MF);
+  EXPECT_TRUE(MBB->livein_empty());
 }
 
 } // end namespace

>From fb398f4c889621497f68a3ff08defe8361ce3d19 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sat, 18 Apr 2026 15:50:40 -0700
Subject: [PATCH 25/32] Enable liveness analysis for MachineLICM

---
 llvm/lib/CodeGen/MachineLICM.cpp | 42 +++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/MachineLICM.cpp b/llvm/lib/CodeGen/MachineLICM.cpp
index 53fbd3bec76cd..6a4911e2c30f0 100644
--- a/llvm/lib/CodeGen/MachineLICM.cpp
+++ b/llvm/lib/CodeGen/MachineLICM.cpp
@@ -35,6 +35,7 @@
 #include "llvm/CodeGen/MachineOperand.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/PseudoSourceValue.h"
+#include "llvm/CodeGen/SparseLiveVariables.h"
 #include "llvm/CodeGen/TargetInstrInfo.h"
 #include "llvm/CodeGen/TargetLowering.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
@@ -127,6 +128,8 @@ namespace {
     bool HasProfileData = false;
     Pass *LegacyPass;
     MachineFunctionAnalysisManager *MFAM;
+    SparseLiveVariables *LV = nullptr;
+    DenseMap<const MachineInstr *, SmallVector<Register, 4>> KilledRegs;
 
     // Various analyses that we use...
     AliasAnalysis *AA = nullptr;               // Alias analysis info.
@@ -244,6 +247,8 @@ namespace {
 
     bool IsGuaranteedToExecute(MachineBasicBlock *BB, MachineLoop *CurLoop);
 
+    void computeKilledRegs(MachineBasicBlock *MBB);
+
     void EnterScope(MachineBasicBlock *MBB);
 
     void ExitScope(MachineBasicBlock *MBB);
@@ -297,6 +302,7 @@ namespace {
     bool runOnMachineFunction(MachineFunction &MF) override;
 
     void getAnalysisUsage(AnalysisUsage &AU) const override {
+      AU.addRequired<SparseLiveVariables>();
       AU.addRequired<MachineLoopInfoWrapperPass>();
       if (DisableHoistingToHotterBlocks != UseBFI::None)
         AU.addRequired<MachineBlockFrequencyInfoWrapperPass>();
@@ -329,6 +335,7 @@ char &llvm::EarlyMachineLICMID = EarlyMachineLICM::ID;
 
 INITIALIZE_PASS_BEGIN(MachineLICM, DEBUG_TYPE,
                       "Machine Loop Invariant Code Motion", false, false)
+INITIALIZE_PASS_DEPENDENCY(SparseLiveVariables)
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
@@ -338,6 +345,7 @@ INITIALIZE_PASS_END(MachineLICM, DEBUG_TYPE,
 
 INITIALIZE_PASS_BEGIN(EarlyMachineLICM, "early-machinelicm",
                       "Early Machine Loop Invariant Code Motion", false, false)
+INITIALIZE_PASS_DEPENDENCY(SparseLiveVariables)
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
@@ -371,6 +379,7 @@ bool MachineLICMImpl::run(MachineFunction &MF) {
   MBFI = DisableHoistingToHotterBlocks != UseBFI::None
              ? GET_RESULT(MachineBlockFrequency, getMBFI, Info)
              : nullptr;
+  LV = LegacyPass ? &LegacyPass->getAnalysis<SparseLiveVariables>() : nullptr;
 
   Changed = FirstInLoop = false;
   const TargetSubtargetInfo &ST = MF.getSubtarget();
@@ -768,9 +777,31 @@ bool MachineLICMImpl::IsGuaranteedToExecute(MachineBasicBlock *BB,
   return true;
 }
 
+void MachineLICMImpl::computeKilledRegs(MachineBasicBlock *MBB) {
+  KilledRegs.clear();
+  if (!LV)
+    return;
+
+  SparseLiveVariables::LivenessTracker Tracker(LV->getLiveOutSet(MBB), MRI);
+  for (const MachineInstr &MI : llvm::reverse(*MBB)) {
+    if (!MI.isDebugInstr() && !MI.isMetaInstruction()) {
+      for (const MachineOperand &MO : MI.operands()) {
+        if (MO.isReg() && MO.isUse()) {
+          Register Reg = MO.getReg();
+          if (Reg.isValid() && Reg.isVirtual() && !Tracker.isLive(Reg))
+            KilledRegs[&MI].push_back(Reg);
+        }
+      }
+      Tracker.stepBackward(MI);
+    }
+  }
+}
+
 void MachineLICMImpl::EnterScope(MachineBasicBlock *MBB) {
   LLVM_DEBUG(dbgs() << "Entering " << printMBBReference(*MBB) << '\n');
 
+  computeKilledRegs(MBB);
+
   // Remember livein register pressure.
   BackTrace.push_back(RegPressure);
 }
@@ -924,6 +955,8 @@ void MachineLICMImpl::InitRegPressure(MachineBasicBlock *BB) {
       InitRegPressure(*BB->pred_begin());
   }
 
+  computeKilledRegs(BB);
+
   for (const MachineInstr &MI : *BB)
     UpdateRegPressure(&MI, /*ConsiderUnseenAsDef=*/true);
 }
@@ -969,7 +1002,14 @@ MachineLICMImpl::calcRegisterCost(const MachineInstr *MI, bool ConsiderSeen,
     if (MO.isDef())
       RCCost = W.RegWeight;
     else {
-      bool isKill = isOperandKill(MO, MRI);
+      bool isKill = false;
+      if (LV) {
+        auto It = KilledRegs.find(MI);
+        if (It != KilledRegs.end())
+          isKill = llvm::is_contained(It->second, Reg);
+      } else {
+        isKill = isOperandKill(MO, MRI);
+      }
       if (isNew && !isKill && ConsiderUnseenAsDef)
         // Haven't seen this, it must be a livein.
         RCCost = W.RegWeight;

>From ff1e91be22d0ed8fb16d3ff4aebb2ea2725291b2 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sat, 18 Apr 2026 19:31:06 -0700
Subject: [PATCH 26/32] Bug fixes triggered by test

---
 llvm/include/llvm/CodeGen/Passes.h            |   4 +-
 .../llvm/CodeGen/SparseLiveVariables.h        |  41 ++-
 llvm/lib/CodeGen/MachineLICM.cpp              |   6 +-
 llvm/lib/CodeGen/SparseLiveVariables.cpp      | 260 +++++++++++++++
 llvm/test/CodeGen/AArch64/O3-pipeline.ll      |   2 +
 .../AArch64/dag-combine-concat-vectors.ll     |  44 +--
 llvm/test/CodeGen/AArch64/pr164181.ll         | 299 +++++++++---------
 llvm/test/CodeGen/RISCV/O3-pipeline.ll        |   2 +
 llvm/test/CodeGen/RISCV/rvv/pr95865.ll        |  72 ++---
 .../RISCV/rvv/vxrm-insert-out-of-loop.ll      | 293 ++++++++---------
 llvm/test/CodeGen/X86/opt-pipeline.ll         |   2 +
 .../CodeGen/SparseLiveVariablesTest.cpp       |  55 ++++
 12 files changed, 719 insertions(+), 361 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h
index 2111260755520..81d10de6e6e57 100644
--- a/llvm/include/llvm/CodeGen/Passes.h
+++ b/llvm/include/llvm/CodeGen/Passes.h
@@ -155,8 +155,8 @@ LLVM_ABI extern char &EdgeBundlesWrapperLegacyID;
 /// variable is life and sets machine operand kill flags.
 LLVM_ABI extern char &LiveVariablesID;
 
-  /// SparseLiveVariables - Sparse Live Variable Analysis.
-  extern char &SparseLiveVariablesID;
+/// SparseLiveVariables - Sparse Live Variable Analysis.
+LLVM_ABI extern char &SparseLiveVariablesID;
 
 /// PHIElimination - This pass eliminates machine instruction PHI nodes
 /// by inserting copy instructions.  This destroys SSA information, but is the
diff --git a/llvm/include/llvm/CodeGen/SparseLiveVariables.h b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
index a98fb3b53be1f..264a96283a973 100644
--- a/llvm/include/llvm/CodeGen/SparseLiveVariables.h
+++ b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
@@ -121,6 +121,11 @@ class SparseLiveVariables : public MachineFunctionPass {
     const SparseBitVector<> &getLiveSet() const { return LiveRegs; }
   };
 
+  /// Returns true if the given MachineBasicBlock has been analyzed.
+  bool hasAnalyzed(const MachineBasicBlock *MBB) const {
+    return BlockLiveness.count(MBB);
+  }
+
   /// Returns the computed Live-In set for the given MachineBasicBlock.
   const SparseBitVector<> &getLiveInSet(const MachineBasicBlock *MBB) const {
     auto It = BlockLiveness.find(MBB);
@@ -143,12 +148,40 @@ class SparseLiveVariables : public MachineFunctionPass {
   /// Note: This performs an O(N) backward traversal from the end of the block.
   bool isLiveAt(Register Reg, const MachineInstr &MI) const;
 
-  /// Returns true if Reg is killed by MI (used by MI and not live after).
-  /// Note: This performs an O(N) backward traversal from the end of the block.
+  /// \brief Perform a single backward step through the instruction.
+  /// \param Reg The virtual register to query.
+  /// \param MI The instruction to evaluate.
   bool isKillAt(Register Reg, const MachineInstr &MI) const;
 
-  /// Validates the computed block liveness against existing MachineBasicBlock
-  /// live-ins.
+  /// \brief Incrementally recomputes liveness for a specific register.
+  ///
+  /// This performs a highly localized $O(V + E)$ recomputation of liveness for
+  /// the given register. It instantly clears the register's liveness from all
+  /// blocks, then reseeds and propagates it from its remaining uses. This
+  /// safely bypasses the "phantom live range" problem where loops artificially
+  /// keep a register alive even after its uses have been deleted.
+  ///
+  /// \param Reg The virtual register to recompute.
+  /// \param IgnoreMI An optional instruction to ignore during recomputation
+  ///                 (useful for removing liveness before an instruction is
+  ///                 physically deleted).
+  void recomputeRegisterLiveness(Register Reg, MachineInstr *IgnoreMI = nullptr);
+
+  /// \brief Update liveness after a pass adds a new instruction.
+  void addInstruction(MachineInstr &MI, MachineBasicBlock *MBB);
+
+  /// \brief Update liveness before a pass removes an instruction.
+  ///
+  /// The pass must call this *before* calling MI.eraseFromParent().
+  void removeInstruction(MachineInstr &MI);
+
+  /// \brief Update liveness after a pass moves an instruction.
+  void handleMove(MachineInstr &MI, MachineBasicBlock *OldBB, MachineBasicBlock *NewBB);
+
+  /// \brief Update the live-in list of each MachineBasicBlock.
+  ///
+  /// This mutates the underlying `MachineBasicBlock` structures to sync their
+  /// state.
   void verifyLiveness(const MachineFunction &MF) const;
 
   /// Update the live-ins of all basic blocks in MF based on computed liveness.
diff --git a/llvm/lib/CodeGen/MachineLICM.cpp b/llvm/lib/CodeGen/MachineLICM.cpp
index 6a4911e2c30f0..87ec978a926ed 100644
--- a/llvm/lib/CodeGen/MachineLICM.cpp
+++ b/llvm/lib/CodeGen/MachineLICM.cpp
@@ -779,7 +779,7 @@ bool MachineLICMImpl::IsGuaranteedToExecute(MachineBasicBlock *BB,
 
 void MachineLICMImpl::computeKilledRegs(MachineBasicBlock *MBB) {
   KilledRegs.clear();
-  if (!LV)
+  if (!LV || !LV->hasAnalyzed(MBB))
     return;
 
   SparseLiveVariables::LivenessTracker Tracker(LV->getLiveOutSet(MBB), MRI);
@@ -1003,10 +1003,12 @@ MachineLICMImpl::calcRegisterCost(const MachineInstr *MI, bool ConsiderSeen,
       RCCost = W.RegWeight;
     else {
       bool isKill = false;
-      if (LV) {
+      if (LV && LV->hasAnalyzed(MI->getParent())) {
         auto It = KilledRegs.find(MI);
         if (It != KilledRegs.end())
           isKill = llvm::is_contained(It->second, Reg);
+        if (!isKill && MRI->hasOneNonDBGUse(Reg))
+          isKill = true;
       } else {
         isKill = isOperandKill(MO, MRI);
       }
diff --git a/llvm/lib/CodeGen/SparseLiveVariables.cpp b/llvm/lib/CodeGen/SparseLiveVariables.cpp
index d390cb218e6b3..d6532fc8de116 100644
--- a/llvm/lib/CodeGen/SparseLiveVariables.cpp
+++ b/llvm/lib/CodeGen/SparseLiveVariables.cpp
@@ -210,4 +210,264 @@ void SparseLiveVariables::updateKillFlags(MachineFunction &MF) const {
   }
 }
 
+void SparseLiveVariables::recomputeRegisterLiveness(Register Reg, MachineInstr *IgnoreMI) {
+  if (!Reg.isVirtual())
+    return;
+
+  // 1. Clear Reg from all blocks
+  for (auto &KV : BlockLiveness) {
+    KV.second.LiveIn.reset(Reg.id());
+    KV.second.LiveOut.reset(Reg.id());
+  }
+
+  // 2. Propagate from all uses
+  SmallVector<MachineBasicBlock *, 8> WorkList;
+
+  for (MachineInstr &UseMI : MRI->use_instructions(Reg)) {
+    if (&UseMI == IgnoreMI)
+      continue;
+
+    MachineBasicBlock *MBB = UseMI.getParent();
+
+    if (UseMI.isPHI()) {
+      // For PHI nodes, the register is live-out of the corresponding predecessor
+      for (unsigned i = 1; i < UseMI.getNumOperands(); i += 2) {
+        if (UseMI.getOperand(i).isReg() && UseMI.getOperand(i).getReg() == Reg) {
+          MachineBasicBlock *Pred = UseMI.getOperand(i + 1).getMBB();
+          auto PredIt = BlockLiveness.find(Pred);
+          if (PredIt != BlockLiveness.end()) {
+            if (!PredIt->second.LiveOut.test(Reg.id())) {
+              PredIt->second.LiveOut.set(Reg.id());
+              WorkList.push_back(Pred);
+            }
+          }
+        }
+      }
+      continue;
+    }
+
+    bool FoundDef = false;
+    for (auto I = MachineBasicBlock::reverse_iterator(&UseMI), E = MBB->rend();
+         I != E; ++I) {
+      if (&*I == IgnoreMI)
+        continue;
+      if (I->definesRegister(Reg, TRI)) {
+        FoundDef = true;
+        break;
+      }
+    }
+
+    if (!FoundDef) {
+      auto It = BlockLiveness.find(MBB);
+      if (It != BlockLiveness.end()) {
+        if (!It->second.LiveIn.test(Reg.id())) {
+          It->second.LiveIn.set(Reg.id());
+          WorkList.push_back(MBB);
+        }
+      }
+    }
+  }
+
+  // 3. Propagate backwards
+  while (!WorkList.empty()) {
+    MachineBasicBlock *Curr = WorkList.pop_back_val();
+
+    for (MachineBasicBlock *Pred : Curr->predecessors()) {
+      auto PredIt = BlockLiveness.find(Pred);
+      if (PredIt == BlockLiveness.end())
+        continue;
+
+      if (!PredIt->second.LiveOut.test(Reg.id())) {
+        PredIt->second.LiveOut.set(Reg.id());
+
+        bool FoundDef = false;
+        for (const MachineInstr &MI : llvm::reverse(*Pred)) {
+          if (&MI == IgnoreMI)
+            continue;
+          if (MI.definesRegister(Reg, TRI)) {
+            FoundDef = true;
+            break;
+          }
+        }
+
+        if (!FoundDef) {
+          if (!PredIt->second.LiveIn.test(Reg.id())) {
+            PredIt->second.LiveIn.set(Reg.id());
+            WorkList.push_back(Pred);
+          }
+        }
+      }
+    }
+  }
+}
+
+void SparseLiveVariables::addInstruction(MachineInstr &MI, MachineBasicBlock *MBB) {
+  if (!MBB)
+    MBB = MI.getParent();
+
+  for (const MachineOperand &MO : MI.operands()) {
+    if (!MO.isReg() || !MO.getReg().isVirtual())
+      continue;
+
+    Register Reg = MO.getReg();
+
+    auto PropagateGrowth = [&](MachineBasicBlock *StartBB) {
+      SmallVector<MachineBasicBlock *, 8> WorkList;
+      WorkList.push_back(StartBB);
+
+      while (!WorkList.empty()) {
+        MachineBasicBlock *Curr = WorkList.pop_back_val();
+        for (MachineBasicBlock *Pred : Curr->predecessors()) {
+          auto PredIt = BlockLiveness.find(Pred);
+          if (PredIt == BlockLiveness.end())
+            continue;
+
+          if (!PredIt->second.LiveOut.test(Reg.id())) {
+            PredIt->second.LiveOut.set(Reg.id());
+
+            bool PredDef = false;
+            for (const MachineInstr &PredMI : llvm::reverse(*Pred)) {
+              if (PredMI.definesRegister(Reg, TRI)) {
+                PredDef = true;
+                break;
+              }
+            }
+
+            if (!PredDef && !PredIt->second.LiveIn.test(Reg.id())) {
+              PredIt->second.LiveIn.set(Reg.id());
+              WorkList.push_back(Pred);
+            }
+          }
+        }
+      }
+    };
+
+    if (MO.isUse()) {
+      if (MI.isPHI()) {
+        MachineBasicBlock *Pred = nullptr;
+        for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
+          if (&MI.getOperand(i) == &MO) {
+            Pred = MI.getOperand(i + 1).getMBB();
+            break;
+          }
+        }
+
+        if (Pred) {
+          auto PredIt = BlockLiveness.find(Pred);
+          if (PredIt != BlockLiveness.end() && !PredIt->second.LiveOut.test(Reg.id())) {
+            PredIt->second.LiveOut.set(Reg.id());
+
+            bool PredDef = false;
+            for (const MachineInstr &PredMI : llvm::reverse(*Pred)) {
+              if (PredMI.definesRegister(Reg, TRI)) {
+                PredDef = true;
+                break;
+              }
+            }
+
+            if (!PredDef && !PredIt->second.LiveIn.test(Reg.id())) {
+              PredIt->second.LiveIn.set(Reg.id());
+              PropagateGrowth(Pred);
+            }
+          }
+        }
+        continue;
+      }
+
+      if (BlockLiveness[MBB].LiveIn.test(Reg.id()))
+        continue;
+
+      bool FoundDef = false;
+      for (auto I = MachineBasicBlock::reverse_iterator(&MI), E = MBB->rend(); I != E; ++I) {
+        if (I->definesRegister(Reg, TRI)) {
+          FoundDef = true;
+          break;
+        }
+      }
+
+      if (!FoundDef) {
+        BlockLiveness[MBB].LiveIn.set(Reg.id());
+        PropagateGrowth(MBB);
+      }
+    } else if (MO.isDef()) {
+      if (!BlockLiveness[MBB].LiveIn.test(Reg.id()))
+        continue;
+
+      bool HasUseAbove = false;
+      for (auto I = MachineBasicBlock::reverse_iterator(&MI), E = MBB->rend(); I != E; ++I) {
+        if (I->readsRegister(Reg, TRI)) {
+          HasUseAbove = true;
+          break;
+        }
+      }
+
+      if (!HasUseAbove) {
+        BlockLiveness[MBB].LiveIn.reset(Reg.id());
+
+        SmallVector<MachineBasicBlock *, 8> WorkList;
+        WorkList.push_back(MBB);
+
+        while (!WorkList.empty()) {
+          MachineBasicBlock *Curr = WorkList.pop_back_val();
+          for (MachineBasicBlock *Pred : Curr->predecessors()) {
+            auto PredIt = BlockLiveness.find(Pred);
+            if (PredIt == BlockLiveness.end())
+              continue;
+
+            if (!PredIt->second.LiveOut.test(Reg.id()))
+              continue;
+
+            bool StillLiveOut = false;
+            for (MachineBasicBlock *Succ : Pred->successors()) {
+              auto SuccIt = BlockLiveness.find(Succ);
+              if (SuccIt != BlockLiveness.end() && SuccIt->second.LiveIn.test(Reg.id())) {
+                StillLiveOut = true;
+                break;
+              }
+            }
+
+            if (!StillLiveOut) {
+              PredIt->second.LiveOut.reset(Reg.id());
+
+              if (PredIt->second.LiveIn.test(Reg.id())) {
+                bool HasUse = false;
+                for (const MachineInstr &PredMI : *Pred) {
+                  if (PredMI.readsRegister(Reg, TRI)) {
+                    HasUse = true;
+                    break;
+                  }
+                  if (PredMI.definesRegister(Reg, TRI)) {
+                    break;
+                  }
+                }
+
+                if (!HasUse) {
+                  PredIt->second.LiveIn.reset(Reg.id());
+                  WorkList.push_back(Pred);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+void SparseLiveVariables::removeInstruction(MachineInstr &MI) {
+  for (const MachineOperand &MO : MI.operands()) {
+    if (MO.isReg() && MO.getReg().isVirtual()) {
+      recomputeRegisterLiveness(MO.getReg(), &MI);
+    }
+  }
+}
+
+void SparseLiveVariables::handleMove(MachineInstr &MI, MachineBasicBlock * /*OldBB*/, MachineBasicBlock * /*NewBB*/) {
+  for (const MachineOperand &MO : MI.operands()) {
+    if (MO.isReg() && MO.getReg().isVirtual()) {
+      recomputeRegisterLiveness(MO.getReg());
+    }
+  }
+}
+
 char &llvm::SparseLiveVariablesID = SparseLiveVariables::ID;
diff --git a/llvm/test/CodeGen/AArch64/O3-pipeline.ll b/llvm/test/CodeGen/AArch64/O3-pipeline.ll
index 546949aa4e209..19b334ad85a0d 100644
--- a/llvm/test/CodeGen/AArch64/O3-pipeline.ll
+++ b/llvm/test/CodeGen/AArch64/O3-pipeline.ll
@@ -157,6 +157,7 @@
 ; CHECK-NEXT:       AArch64 Store Pair Suppression
 ; CHECK-NEXT:       AArch64 SIMD instructions optimization pass
 ; CHECK-NEXT:       AArch64 Stack Tagging PreRA
+; CHECK-NEXT:       Sparse Live Variable Analysis
 ; CHECK-NEXT:       MachineDominator Tree Construction
 ; CHECK-NEXT:       Machine Natural Loop Construction
 ; CHECK-NEXT:       Machine Block Frequency Analysis
@@ -199,6 +200,7 @@
 ; CHECK-NEXT:       Stack Slot Coloring
 ; CHECK-NEXT:       AArch64 SRLT Define Super-Regs Pass
 ; CHECK-NEXT:       Machine Copy Propagation Pass
+; CHECK-NEXT:       Sparse Live Variable Analysis
 ; CHECK-NEXT:       Machine Loop Invariant Code Motion
 ; CHECK-NEXT:       AArch64 Redundant Copy Elimination
 ; CHECK-NEXT:       A57 FP Anti-dependency breaker
diff --git a/llvm/test/CodeGen/AArch64/dag-combine-concat-vectors.ll b/llvm/test/CodeGen/AArch64/dag-combine-concat-vectors.ll
index ae3a0e2ac1b6b..028e196486646 100644
--- a/llvm/test/CodeGen/AArch64/dag-combine-concat-vectors.ll
+++ b/llvm/test/CodeGen/AArch64/dag-combine-concat-vectors.ll
@@ -5,6 +5,8 @@
 
 declare void @llvm.masked.scatter.nxv16i8.nxv16p0(<vscale x 16 x i8>, <vscale x 16 x ptr>, i32 immarg, <vscale x 16 x i1>)
 
+; MachineLICM uses SparseLiveVariables to hoist the unpack instructions out
+; of the loop body, while keeping the masked scatter instruction inside the loop.
 define fastcc i8 @allocno_reload_assign(ptr %p) {
 ; CHECK-LABEL: allocno_reload_assign:
 ; CHECK:       // %bb.0:
@@ -18,14 +20,28 @@ define fastcc i8 @allocno_reload_assign(ptr %p) {
 ; CHECK-NEXT:    fmov w8, s0
 ; CHECK-NEXT:    movi v0.2d, #0000000000000000
 ; CHECK-NEXT:    mvn w8, w8
+; CHECK-NEXT:    uunpklo z1.h, z0.b
+; CHECK-NEXT:    uunpkhi z2.h, z0.b
 ; CHECK-NEXT:    sbfx x8, x8, #0, #1
 ; CHECK-NEXT:    whilelo p0.b, xzr, x8
+; CHECK-NEXT:    uunpklo z3.s, z1.h
+; CHECK-NEXT:    uunpkhi z4.s, z1.h
+; CHECK-NEXT:    uunpklo z6.s, z2.h
+; CHECK-NEXT:    uunpkhi z16.s, z2.h
 ; CHECK-NEXT:    punpklo p1.h, p0.b
 ; CHECK-NEXT:    punpkhi p0.h, p0.b
 ; CHECK-NEXT:    punpklo p2.h, p1.b
 ; CHECK-NEXT:    punpkhi p4.h, p1.b
+; CHECK-NEXT:    uunpklo z1.d, z3.s
+; CHECK-NEXT:    uunpkhi z2.d, z3.s
 ; CHECK-NEXT:    punpklo p6.h, p0.b
+; CHECK-NEXT:    uunpklo z3.d, z4.s
+; CHECK-NEXT:    uunpkhi z4.d, z4.s
 ; CHECK-NEXT:    punpkhi p0.h, p0.b
+; CHECK-NEXT:    uunpklo z5.d, z6.s
+; CHECK-NEXT:    uunpkhi z6.d, z6.s
+; CHECK-NEXT:    uunpklo z7.d, z16.s
+; CHECK-NEXT:    uunpkhi z16.d, z16.s
 ; CHECK-NEXT:    punpklo p1.h, p2.b
 ; CHECK-NEXT:    punpkhi p2.h, p2.b
 ; CHECK-NEXT:    punpklo p3.h, p4.b
@@ -35,28 +51,14 @@ define fastcc i8 @allocno_reload_assign(ptr %p) {
 ; CHECK-NEXT:    punpklo p7.h, p0.b
 ; CHECK-NEXT:    punpkhi p0.h, p0.b
 ; CHECK-NEXT:  .LBB0_1: // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    uunpklo z1.h, z0.b
-; CHECK-NEXT:    uunpklo z2.s, z1.h
-; CHECK-NEXT:    uunpkhi z1.s, z1.h
-; CHECK-NEXT:    uunpklo z3.d, z2.s
-; CHECK-NEXT:    uunpkhi z2.d, z2.s
-; CHECK-NEXT:    st1b { z3.d }, p1, [z0.d]
+; CHECK-NEXT:    st1b { z1.d }, p1, [z0.d]
 ; CHECK-NEXT:    st1b { z2.d }, p2, [z0.d]
-; CHECK-NEXT:    uunpklo z2.d, z1.s
-; CHECK-NEXT:    uunpkhi z1.d, z1.s
-; CHECK-NEXT:    st1b { z2.d }, p3, [z0.d]
-; CHECK-NEXT:    uunpkhi z2.h, z0.b
-; CHECK-NEXT:    uunpklo z3.s, z2.h
-; CHECK-NEXT:    uunpkhi z2.s, z2.h
-; CHECK-NEXT:    st1b { z1.d }, p4, [z0.d]
-; CHECK-NEXT:    uunpklo z1.d, z3.s
-; CHECK-NEXT:    st1b { z1.d }, p5, [z0.d]
-; CHECK-NEXT:    uunpkhi z1.d, z3.s
-; CHECK-NEXT:    st1b { z1.d }, p6, [z0.d]
-; CHECK-NEXT:    uunpklo z1.d, z2.s
-; CHECK-NEXT:    st1b { z1.d }, p7, [z0.d]
-; CHECK-NEXT:    uunpkhi z1.d, z2.s
-; CHECK-NEXT:    st1b { z1.d }, p0, [z0.d]
+; CHECK-NEXT:    st1b { z3.d }, p3, [z0.d]
+; CHECK-NEXT:    st1b { z4.d }, p4, [z0.d]
+; CHECK-NEXT:    st1b { z5.d }, p5, [z0.d]
+; CHECK-NEXT:    st1b { z6.d }, p6, [z0.d]
+; CHECK-NEXT:    st1b { z7.d }, p7, [z0.d]
+; CHECK-NEXT:    st1b { z16.d }, p0, [z0.d]
 ; CHECK-NEXT:    str p8, [x0]
 ; CHECK-NEXT:    b .LBB0_1
   br label %1
diff --git a/llvm/test/CodeGen/AArch64/pr164181.ll b/llvm/test/CodeGen/AArch64/pr164181.ll
index 72b2a77e51c06..6c0063f6482b3 100644
--- a/llvm/test/CodeGen/AArch64/pr164181.ll
+++ b/llvm/test/CodeGen/AArch64/pr164181.ll
@@ -6,6 +6,11 @@
 ; When rematting an instruction we need to make sure to constrain the newly
 ; allocated register to both the rematted def's reg class and the use's reg
 ; class.
+;
+; MachineLICM estimates loop backedge register pressure, thereby preventing
+; constants from being materialized at the bottom of the loop and kept alive
+; across the entire backedge. As a result, the register pressure in the inner
+; loops of this function is reduced see `mov w4, #18984` and `movk x8, #58909, lsl #16`.
 
 target triple = "aarch64-unknown-linux-gnu"
 
@@ -26,65 +31,62 @@ define void @f(i1 %var_0, i16 %var_1, i64 %var_2, i8 %var_3, i16 %var_4, i1 %var
 ; CHECK-NEXT:    stp x22, x21, [sp, #208] // 16-byte Folded Spill
 ; CHECK-NEXT:    stp x20, x19, [sp, #224] // 16-byte Folded Spill
 ; CHECK-NEXT:    str w6, [sp, #20] // 4-byte Spill
-; CHECK-NEXT:    str w4, [sp, #72] // 4-byte Spill
-; CHECK-NEXT:    str w3, [sp, #112] // 4-byte Spill
+; CHECK-NEXT:    str w4, [sp, #76] // 4-byte Spill
+; CHECK-NEXT:    str w3, [sp, #116] // 4-byte Spill
 ; CHECK-NEXT:    str w5, [sp, #36] // 4-byte Spill
 ; CHECK-NEXT:    tbz w5, #0, .LBB0_40
 ; CHECK-NEXT:  // %bb.1: // %for.body41.lr.ph
 ; CHECK-NEXT:    ldr x4, [sp, #312]
-; CHECK-NEXT:    ldr x14, [sp, #280]
+; CHECK-NEXT:    ldr x15, [sp, #280]
 ; CHECK-NEXT:    tbz w0, #0, .LBB0_39
 ; CHECK-NEXT:  // %bb.2: // %for.body41.us.preheader
 ; CHECK-NEXT:    ldrb w8, [sp, #368]
-; CHECK-NEXT:    ldrb w12, [sp, #256]
-; CHECK-NEXT:    ldr w26, [sp, #264]
-; CHECK-NEXT:    adrp x20, :got:var_50
-; CHECK-NEXT:    mov x28, #-1 // =0xffffffffffffffff
-; CHECK-NEXT:    mov w21, #36006 // =0x8ca6
-; CHECK-NEXT:    ldr x11, [sp, #376]
-; CHECK-NEXT:    ldrb w13, [sp, #360]
-; CHECK-NEXT:    ldp x17, x16, [sp, #296]
+; CHECK-NEXT:    ldrb w11, [sp, #256]
+; CHECK-NEXT:    ldr w13, [sp, #264]
+; CHECK-NEXT:    adrp x21, :got:var_50
+; CHECK-NEXT:    add x28, x15, #120
+; CHECK-NEXT:    mov w3, #36006 // =0x8ca6
+; CHECK-NEXT:    ldr x12, [sp, #376]
+; CHECK-NEXT:    ldrb w14, [sp, #360]
+; CHECK-NEXT:    ldp x18, x17, [sp, #296]
 ; CHECK-NEXT:    mov w22, #1 // =0x1
-; CHECK-NEXT:    add x27, x14, #120
-; CHECK-NEXT:    ldr x18, [sp, #288]
-; CHECK-NEXT:    ldr x7, [sp, #272]
-; CHECK-NEXT:    ldr x5, [sp, #248]
 ; CHECK-NEXT:    mov x10, xzr
+; CHECK-NEXT:    ldr x7, [sp, #288]
+; CHECK-NEXT:    ldr x19, [sp, #272]
+; CHECK-NEXT:    ldr x5, [sp, #248]
 ; CHECK-NEXT:    mov w23, wzr
-; CHECK-NEXT:    mov w30, wzr
-; CHECK-NEXT:    ldrb w19, [sp, #240]
-; CHECK-NEXT:    mov w25, wzr
-; CHECK-NEXT:    mov x24, xzr
-; CHECK-NEXT:    str w8, [sp, #108] // 4-byte Spill
-; CHECK-NEXT:    mov x3, x26
+; CHECK-NEXT:    mov w27, wzr
+; CHECK-NEXT:    mov w20, wzr
+; CHECK-NEXT:    ldrb w24, [sp, #240]
+; CHECK-NEXT:    mov x25, xzr
+; CHECK-NEXT:    str w8, [sp, #112] // 4-byte Spill
 ; CHECK-NEXT:    ldp x9, x8, [sp, #344]
-; CHECK-NEXT:    str w12, [sp, #92] // 4-byte Spill
-; CHECK-NEXT:    mov w12, #1 // =0x1
-; CHECK-NEXT:    bic w12, w12, w0
-; CHECK-NEXT:    str w12, [sp, #76] // 4-byte Spill
-; CHECK-NEXT:    mov w12, #48 // =0x30
+; CHECK-NEXT:    str w11, [sp, #100] // 4-byte Spill
+; CHECK-NEXT:    mov w11, #1 // =0x1
+; CHECK-NEXT:    bic w11, w11, w0
+; CHECK-NEXT:    str w11, [sp, #84] // 4-byte Spill
+; CHECK-NEXT:    mov w11, #48 // =0x30
 ; CHECK-NEXT:    str x9, [sp, #136] // 8-byte Spill
-; CHECK-NEXT:    ldp x9, x15, [sp, #328]
-; CHECK-NEXT:    madd x8, x8, x12, x9
+; CHECK-NEXT:    ldp x9, x16, [sp, #328]
+; CHECK-NEXT:    madd x8, x8, x11, x9
 ; CHECK-NEXT:    str x8, [sp, #64] // 8-byte Spill
-; CHECK-NEXT:    add x8, x26, w26, uxtw #1
-; CHECK-NEXT:    ldr x20, [x20, :got_lo12:var_50]
-; CHECK-NEXT:    str x26, [sp, #96] // 8-byte Spill
-; CHECK-NEXT:    str x14, [sp, #152] // 8-byte Spill
-; CHECK-NEXT:    lsl x6, x8, #3
-; CHECK-NEXT:    add x8, x14, #120
+; CHECK-NEXT:    add x8, x13, w13, uxtw #1
+; CHECK-NEXT:    ldr x21, [x21, :got_lo12:var_50]
+; CHECK-NEXT:    str x15, [sp, #152] // 8-byte Spill
 ; CHECK-NEXT:    str x4, [sp, #24] // 8-byte Spill
-; CHECK-NEXT:    str w19, [sp, #16] // 4-byte Spill
-; CHECK-NEXT:    str x8, [sp, #80] // 8-byte Spill
+; CHECK-NEXT:    str x13, [sp, #104] // 8-byte Spill
+; CHECK-NEXT:    str w24, [sp, #16] // 4-byte Spill
+; CHECK-NEXT:    str x28, [sp, #88] // 8-byte Spill
+; CHECK-NEXT:    lsl x6, x8, #3
 ; CHECK-NEXT:    b .LBB0_4
 ; CHECK-NEXT:    .p2align 5, , 16
 ; CHECK-NEXT:  .LBB0_3: // in Loop: Header=BB0_4 Depth=1
-; CHECK-NEXT:    ldr w19, [sp, #16] // 4-byte Reload
-; CHECK-NEXT:    ldr x24, [sp, #40] // 8-byte Reload
-; CHECK-NEXT:    ldr x14, [sp, #152] // 8-byte Reload
+; CHECK-NEXT:    ldr w24, [sp, #16] // 4-byte Reload
+; CHECK-NEXT:    ldr x25, [sp, #40] // 8-byte Reload
+; CHECK-NEXT:    ldr x15, [sp, #152] // 8-byte Reload
 ; CHECK-NEXT:    mov w23, #1 // =0x1
-; CHECK-NEXT:    mov w30, #1 // =0x1
-; CHECK-NEXT:    mov w25, w19
+; CHECK-NEXT:    mov w27, #1 // =0x1
+; CHECK-NEXT:    mov w20, w24
 ; CHECK-NEXT:  .LBB0_4: // %for.body41.us
 ; CHECK-NEXT:    // =>This Loop Header: Depth=1
 ; CHECK-NEXT:    // Child Loop BB0_6 Depth 2
@@ -94,20 +96,20 @@ define void @f(i1 %var_0, i16 %var_1, i64 %var_2, i8 %var_3, i16 %var_4, i1 %var
 ; CHECK-NEXT:    // Child Loop BB0_28 Depth 5
 ; CHECK-NEXT:    // Child Loop BB0_36 Depth 5
 ; CHECK-NEXT:    ldr w8, [sp, #20] // 4-byte Reload
-; CHECK-NEXT:    mov x12, x24
-; CHECK-NEXT:    str x24, [sp, #48] // 8-byte Spill
-; CHECK-NEXT:    str w8, [x14]
+; CHECK-NEXT:    mov x11, x25
+; CHECK-NEXT:    str x25, [sp, #48] // 8-byte Spill
+; CHECK-NEXT:    str w8, [x15]
 ; CHECK-NEXT:    mov w8, #1 // =0x1
-; CHECK-NEXT:    strb w19, [x14]
+; CHECK-NEXT:    strb w24, [x15]
 ; CHECK-NEXT:    b .LBB0_6
 ; CHECK-NEXT:    .p2align 5, , 16
 ; CHECK-NEXT:  .LBB0_5: // %for.cond.cleanup93.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_6 Depth=2
 ; CHECK-NEXT:    ldr w9, [sp, #36] // 4-byte Reload
 ; CHECK-NEXT:    ldr x4, [sp, #24] // 8-byte Reload
-; CHECK-NEXT:    ldp x24, x12, [sp, #48] // 16-byte Folded Reload
+; CHECK-NEXT:    ldp x25, x11, [sp, #48] // 16-byte Folded Reload
 ; CHECK-NEXT:    mov x22, xzr
-; CHECK-NEXT:    mov w25, wzr
+; CHECK-NEXT:    mov w20, wzr
 ; CHECK-NEXT:    mov w8, wzr
 ; CHECK-NEXT:    tbz w9, #0, .LBB0_3
 ; CHECK-NEXT:  .LBB0_6: // %for.body67.us
@@ -118,20 +120,19 @@ define void @f(i1 %var_0, i16 %var_1, i64 %var_2, i8 %var_3, i16 %var_4, i1 %var
 ; CHECK-NEXT:    // Child Loop BB0_11 Depth 5
 ; CHECK-NEXT:    // Child Loop BB0_28 Depth 5
 ; CHECK-NEXT:    // Child Loop BB0_36 Depth 5
-; CHECK-NEXT:    str x12, [sp, #40] // 8-byte Spill
-; CHECK-NEXT:    cmn x24, #30
-; CHECK-NEXT:    mov x12, #-30 // =0xffffffffffffffe2
-; CHECK-NEXT:    add x19, x4, w8, sxtw #2
+; CHECK-NEXT:    str x11, [sp, #40] // 8-byte Spill
+; CHECK-NEXT:    cmn x25, #30
+; CHECK-NEXT:    mov x11, #-30 // =0xffffffffffffffe2
 ; CHECK-NEXT:    mov x9, xzr
-; CHECK-NEXT:    csel x12, x24, x12, lo
-; CHECK-NEXT:    mov w4, w30
-; CHECK-NEXT:    str x12, [sp, #56] // 8-byte Spill
+; CHECK-NEXT:    csel x11, x25, x11, lo
+; CHECK-NEXT:    add x25, x4, w8, sxtw #2
+; CHECK-NEXT:    mov w4, w27
+; CHECK-NEXT:    str x11, [sp, #56] // 8-byte Spill
 ; CHECK-NEXT:    b .LBB0_8
 ; CHECK-NEXT:    .p2align 5, , 16
 ; CHECK-NEXT:  .LBB0_7: // %for.cond.cleanup98.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_8 Depth=3
-; CHECK-NEXT:    ldr w4, [sp, #72] // 4-byte Reload
-; CHECK-NEXT:    ldr w23, [sp, #128] // 4-byte Reload
+; CHECK-NEXT:    ldp w4, w23, [sp, #76] // 8-byte Folded Reload
 ; CHECK-NEXT:    mov w9, #1 // =0x1
 ; CHECK-NEXT:    mov x22, xzr
 ; CHECK-NEXT:    tbnz w0, #0, .LBB0_5
@@ -144,30 +145,30 @@ define void @f(i1 %var_0, i16 %var_1, i64 %var_2, i8 %var_3, i16 %var_4, i1 %var
 ; CHECK-NEXT:    // Child Loop BB0_28 Depth 5
 ; CHECK-NEXT:    // Child Loop BB0_36 Depth 5
 ; CHECK-NEXT:    ldr x8, [sp, #64] // 8-byte Reload
-; CHECK-NEXT:    mov w14, #1152 // =0x480
+; CHECK-NEXT:    mov w11, #1152 // =0x480
 ; CHECK-NEXT:    mov w24, #1 // =0x1
-; CHECK-NEXT:    mov w12, wzr
+; CHECK-NEXT:    mov w15, #1 // =0x1
+; CHECK-NEXT:    mov w30, wzr
+; CHECK-NEXT:    mov w27, w4
 ; CHECK-NEXT:    str wzr, [sp, #132] // 4-byte Spill
-; CHECK-NEXT:    mov w30, w4
-; CHECK-NEXT:    madd x8, x9, x14, x8
-; CHECK-NEXT:    mov w14, #1 // =0x1
+; CHECK-NEXT:    madd x8, x9, x11, x8
+; CHECK-NEXT:    mov w11, w20
 ; CHECK-NEXT:    str x8, [sp, #120] // 8-byte Spill
 ; CHECK-NEXT:    add x8, x9, x9, lsl #1
 ; CHECK-NEXT:    lsl x26, x8, #4
 ; CHECK-NEXT:    sxtb w8, w23
-; CHECK-NEXT:    mov w23, w25
-; CHECK-NEXT:    str w8, [sp, #116] // 4-byte Spill
+; CHECK-NEXT:    and w8, w8, w8, asr #31
+; CHECK-NEXT:    str w8, [sp, #80] // 4-byte Spill
 ; CHECK-NEXT:    b .LBB0_10
 ; CHECK-NEXT:    .p2align 5, , 16
 ; CHECK-NEXT:  .LBB0_9: // %for.cond510.preheader.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
-; CHECK-NEXT:    ldr w23, [sp, #92] // 4-byte Reload
+; CHECK-NEXT:    ldr w11, [sp, #100] // 4-byte Reload
 ; CHECK-NEXT:    mov x22, x8
-; CHECK-NEXT:    ldr x3, [sp, #96] // 8-byte Reload
-; CHECK-NEXT:    ldr x27, [sp, #80] // 8-byte Reload
-; CHECK-NEXT:    mov x28, #-1 // =0xffffffffffffffff
-; CHECK-NEXT:    mov x14, xzr
-; CHECK-NEXT:    ldr w8, [sp, #76] // 4-byte Reload
+; CHECK-NEXT:    ldr x13, [sp, #104] // 8-byte Reload
+; CHECK-NEXT:    ldr x28, [sp, #88] // 8-byte Reload
+; CHECK-NEXT:    mov x15, xzr
+; CHECK-NEXT:    ldr w8, [sp, #84] // 4-byte Reload
 ; CHECK-NEXT:    tbz w8, #31, .LBB0_7
 ; CHECK-NEXT:  .LBB0_10: // %for.body99.us
 ; CHECK-NEXT:    // Parent Loop BB0_4 Depth=1
@@ -177,9 +178,7 @@ define void @f(i1 %var_0, i16 %var_1, i64 %var_2, i8 %var_3, i16 %var_4, i1 %var
 ; CHECK-NEXT:    // Child Loop BB0_11 Depth 5
 ; CHECK-NEXT:    // Child Loop BB0_28 Depth 5
 ; CHECK-NEXT:    // Child Loop BB0_36 Depth 5
-; CHECK-NEXT:    ldr w8, [sp, #116] // 4-byte Reload
-; CHECK-NEXT:    and w8, w8, w8, asr #31
-; CHECK-NEXT:    str w8, [sp, #128] // 4-byte Spill
+; CHECK-NEXT:    mov w20, w11
 ; CHECK-NEXT:    .p2align 5, , 16
 ; CHECK-NEXT:  .LBB0_11: // %for.body113.us
 ; CHECK-NEXT:    // Parent Loop BB0_4 Depth=1
@@ -190,74 +189,70 @@ define void @f(i1 %var_0, i16 %var_1, i64 %var_2, i8 %var_3, i16 %var_4, i1 %var
 ; CHECK-NEXT:    tbnz w0, #0, .LBB0_11
 ; CHECK-NEXT:  // %bb.12: // %for.cond131.preheader.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
-; CHECK-NEXT:    ldr w8, [sp, #112] // 4-byte Reload
-; CHECK-NEXT:    mov w4, #1 // =0x1
-; CHECK-NEXT:    strb w8, [x18]
+; CHECK-NEXT:    ldr w8, [sp, #116] // 4-byte Reload
+; CHECK-NEXT:    mov w11, #1 // =0x1
+; CHECK-NEXT:    mov w4, #18984 // =0x4a28
+; CHECK-NEXT:    strb w8, [x7]
 ; CHECK-NEXT:    ldr x8, [sp, #120] // 8-byte Reload
 ; CHECK-NEXT:    ldrh w8, [x8]
-; CHECK-NEXT:    cbnz w4, .LBB0_14
+; CHECK-NEXT:    cbnz w11, .LBB0_14
 ; CHECK-NEXT:  // %bb.13: // %cond.true146.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
-; CHECK-NEXT:    ldrsb w4, [x27, x3]
+; CHECK-NEXT:    ldrsb w11, [x28, x13]
 ; CHECK-NEXT:    b .LBB0_15
 ; CHECK-NEXT:    .p2align 5, , 16
 ; CHECK-NEXT:  .LBB0_14: // in Loop: Header=BB0_10 Depth=4
-; CHECK-NEXT:    mov w4, wzr
+; CHECK-NEXT:    mov w11, wzr
 ; CHECK-NEXT:  .LBB0_15: // %cond.end154.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
-; CHECK-NEXT:    mov w25, #18984 // =0x4a28
-; CHECK-NEXT:    mul w8, w8, w25
+; CHECK-NEXT:    mul w8, w8, w4
 ; CHECK-NEXT:    and w8, w8, #0xfff8
-; CHECK-NEXT:    lsl w8, w8, w4
+; CHECK-NEXT:    lsl w8, w8, w11
+; CHECK-NEXT:    ldr w11, [sp, #132] // 4-byte Reload
 ; CHECK-NEXT:    cbz w8, .LBB0_17
 ; CHECK-NEXT:  // %bb.16: // %if.then.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
-; CHECK-NEXT:    str wzr, [sp, #132] // 4-byte Spill
-; CHECK-NEXT:    str wzr, [x18]
+; CHECK-NEXT:    mov w11, wzr
+; CHECK-NEXT:    str wzr, [x7]
 ; CHECK-NEXT:  .LBB0_17: // %if.end.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
-; CHECK-NEXT:    ldr w8, [sp, #108] // 4-byte Reload
-; CHECK-NEXT:    mov w4, #18984 // =0x4a28
-; CHECK-NEXT:    mov w25, w23
-; CHECK-NEXT:    strb w8, [x18]
-; CHECK-NEXT:    ldrsb w8, [x27, x3]
+; CHECK-NEXT:    ldr w8, [sp, #112] // 4-byte Reload
+; CHECK-NEXT:    strb w8, [x7]
+; CHECK-NEXT:    ldrsb w8, [x28, x13]
 ; CHECK-NEXT:    lsl w8, w4, w8
-; CHECK-NEXT:    mov x4, #-18403 // =0xffffffffffffb81d
-; CHECK-NEXT:    movk x4, #58909, lsl #16
 ; CHECK-NEXT:    cbz w8, .LBB0_19
 ; CHECK-NEXT:  // %bb.18: // %if.then.us.2
 ; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
-; CHECK-NEXT:    str wzr, [sp, #132] // 4-byte Spill
-; CHECK-NEXT:    strb wzr, [x18]
+; CHECK-NEXT:    mov w11, wzr
+; CHECK-NEXT:    strb wzr, [x7]
 ; CHECK-NEXT:  .LBB0_19: // %if.then.us.5
 ; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
-; CHECK-NEXT:    ldr w23, [sp, #132] // 4-byte Reload
 ; CHECK-NEXT:    mov w8, #29625 // =0x73b9
 ; CHECK-NEXT:    movk w8, #21515, lsl #16
-; CHECK-NEXT:    cmp w23, w8
-; CHECK-NEXT:    csel w23, w23, w8, lt
-; CHECK-NEXT:    str w23, [sp, #132] // 4-byte Spill
-; CHECK-NEXT:    tbz w0, #0, .LBB0_21
+; CHECK-NEXT:    cmp w11, w8
+; CHECK-NEXT:    csel w11, w11, w8, lt
+; CHECK-NEXT:    tbz w0, #0, .LBB0_22
 ; CHECK-NEXT:  // %bb.20: // in Loop: Header=BB0_10 Depth=4
 ; CHECK-NEXT:    mov w8, wzr
-; CHECK-NEXT:    b .LBB0_22
-; CHECK-NEXT:    .p2align 5, , 16
-; CHECK-NEXT:  .LBB0_21: // %cond.true146.us.7
-; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
-; CHECK-NEXT:    ldrsb w8, [x27, x3]
-; CHECK-NEXT:  .LBB0_22: // %cond.end154.us.7
-; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
-; CHECK-NEXT:    mov w23, #18984 // =0x4a28
-; CHECK-NEXT:    mov w3, #149 // =0x95
-; CHECK-NEXT:    lsl w8, w23, w8
-; CHECK-NEXT:    cbz w8, .LBB0_24
-; CHECK-NEXT:  // %bb.23: // %if.then.us.7
+; CHECK-NEXT:    lsl w8, w4, w8
+; CHECK-NEXT:    cbz w8, .LBB0_23
+; CHECK-NEXT:  .LBB0_21: // %if.then.us.7
 ; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
 ; CHECK-NEXT:    ldr x8, [sp, #152] // 8-byte Reload
 ; CHECK-NEXT:    str wzr, [sp, #132] // 4-byte Spill
 ; CHECK-NEXT:    str wzr, [x8]
+; CHECK-NEXT:    b .LBB0_24
+; CHECK-NEXT:    .p2align 5, , 16
+; CHECK-NEXT:  .LBB0_22: // %cond.true146.us.7
+; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
+; CHECK-NEXT:    ldrsb w8, [x28, x13]
+; CHECK-NEXT:    lsl w8, w4, w8
+; CHECK-NEXT:    cbnz w8, .LBB0_21
+; CHECK-NEXT:  .LBB0_23: // in Loop: Header=BB0_10 Depth=4
+; CHECK-NEXT:    str w11, [sp, #132] // 4-byte Spill
 ; CHECK-NEXT:  .LBB0_24: // %if.end.us.7
 ; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
+; CHECK-NEXT:    mov w4, #149 // =0x95
 ; CHECK-NEXT:    mov x23, xzr
 ; CHECK-NEXT:    b .LBB0_28
 ; CHECK-NEXT:    .p2align 5, , 16
@@ -266,20 +261,20 @@ define void @f(i1 %var_0, i16 %var_1, i64 %var_2, i8 %var_3, i16 %var_4, i1 %var
 ; CHECK-NEXT:    ldrsb w4, [x10]
 ; CHECK-NEXT:  .LBB0_26: // %cond.end345.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_28 Depth=5
-; CHECK-NEXT:    strh w4, [x18]
-; CHECK-NEXT:    mul x4, x22, x28
-; CHECK-NEXT:    adrp x22, :got:var_46
+; CHECK-NEXT:    strh w4, [x7]
+; CHECK-NEXT:    mov x4, #-1 // =0xffffffffffffffff
 ; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mul x4, x22, x4
+; CHECK-NEXT:    adrp x22, :got:var_46
 ; CHECK-NEXT:    ldr x22, [x22, :got_lo12:var_46]
 ; CHECK-NEXT:    str x4, [x22]
-; CHECK-NEXT:    mov x4, #-18403 // =0xffffffffffffb81d
-; CHECK-NEXT:    movk x4, #58909, lsl #16
+; CHECK-NEXT:    mov w4, #149 // =0x95
 ; CHECK-NEXT:  .LBB0_27: // %for.inc371.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_28 Depth=5
 ; CHECK-NEXT:    mov w22, #-18978 // =0xffffb5de
 ; CHECK-NEXT:    orr x23, x23, #0x1
 ; CHECK-NEXT:    mov x24, xzr
-; CHECK-NEXT:    mul w12, w12, w22
+; CHECK-NEXT:    mul w30, w30, w22
 ; CHECK-NEXT:    mov x22, x5
 ; CHECK-NEXT:    tbz w0, #0, .LBB0_33
 ; CHECK-NEXT:  .LBB0_28: // %if.then222.us
@@ -288,33 +283,35 @@ define void @f(i1 %var_0, i16 %var_1, i64 %var_2, i8 %var_3, i16 %var_4, i1 %var
 ; CHECK-NEXT:    // Parent Loop BB0_8 Depth=3
 ; CHECK-NEXT:    // Parent Loop BB0_10 Depth=4
 ; CHECK-NEXT:    // => This Inner Loop Header: Depth=5
-; CHECK-NEXT:    adrp x27, :got:var_32
-; CHECK-NEXT:    ldur w8, [x19, #-12]
-; CHECK-NEXT:    ldr x27, [x27, :got_lo12:var_32]
-; CHECK-NEXT:    strh w8, [x27]
-; CHECK-NEXT:    sxtb w8, w25
-; CHECK-NEXT:    strb w3, [x16]
-; CHECK-NEXT:    bic w25, w8, w8, asr #31
-; CHECK-NEXT:    tst w13, #0xff
+; CHECK-NEXT:    adrp x11, :got:var_32
+; CHECK-NEXT:    ldur w8, [x25, #-12]
+; CHECK-NEXT:    ldr x11, [x11, :got_lo12:var_32]
+; CHECK-NEXT:    strh w8, [x11]
+; CHECK-NEXT:    sxtb w8, w20
+; CHECK-NEXT:    strb w4, [x17]
+; CHECK-NEXT:    bic w20, w8, w8, asr #31
+; CHECK-NEXT:    tst w14, #0xff
 ; CHECK-NEXT:    b.eq .LBB0_30
 ; CHECK-NEXT:  // %bb.29: // %if.then254.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_28 Depth=5
-; CHECK-NEXT:    ldrh w8, [x26, x14, lsl #1]
-; CHECK-NEXT:    adrp x27, :got:var_35
-; CHECK-NEXT:    ldr x27, [x27, :got_lo12:var_35]
+; CHECK-NEXT:    ldrh w8, [x26, x15, lsl #1]
+; CHECK-NEXT:    adrp x11, :got:var_35
+; CHECK-NEXT:    ldr x11, [x11, :got_lo12:var_35]
 ; CHECK-NEXT:    cmp w8, #0
-; CHECK-NEXT:    csel x8, xzr, x7, eq
-; CHECK-NEXT:    str x8, [x27]
-; CHECK-NEXT:    strh w1, [x17]
+; CHECK-NEXT:    csel x8, xzr, x19, eq
+; CHECK-NEXT:    str x8, [x11]
+; CHECK-NEXT:    strh w1, [x18]
 ; CHECK-NEXT:  .LBB0_30: // %if.end282.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_28 Depth=5
-; CHECK-NEXT:    orr x27, x24, x4
+; CHECK-NEXT:    mov x8, #-18403 // =0xffffffffffffb81d
+; CHECK-NEXT:    movk x8, #58909, lsl #16
+; CHECK-NEXT:    orr x11, x24, x8
 ; CHECK-NEXT:    adrp x8, :got:var_39
-; CHECK-NEXT:    str x27, [x18]
+; CHECK-NEXT:    str x11, [x7]
 ; CHECK-NEXT:    ldr x8, [x8, :got_lo12:var_39]
 ; CHECK-NEXT:    str x10, [x8]
 ; CHECK-NEXT:    ldrb w8, [x6, x9]
-; CHECK-NEXT:    str x8, [x18]
+; CHECK-NEXT:    str x8, [x7]
 ; CHECK-NEXT:    mov w8, #1 // =0x1
 ; CHECK-NEXT:    cbnz x2, .LBB0_27
 ; CHECK-NEXT:  // %bb.31: // %if.then327.us
@@ -326,31 +323,31 @@ define void @f(i1 %var_0, i16 %var_1, i64 %var_2, i8 %var_3, i16 %var_4, i1 %var
 ; CHECK-NEXT:    .p2align 5, , 16
 ; CHECK-NEXT:  .LBB0_33: // %for.cond376.preheader.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_10 Depth=4
-; CHECK-NEXT:    mov w3, #1152 // =0x480
+; CHECK-NEXT:    mov x24, x11
+; CHECK-NEXT:    mov w11, #1152 // =0x480
 ; CHECK-NEXT:    mov x22, xzr
 ; CHECK-NEXT:    mov w4, wzr
-; CHECK-NEXT:    mov x24, x27
-; CHECK-NEXT:    lsl x23, x14, #1
-; CHECK-NEXT:    mov x27, #-1 // =0xffffffffffffffff
-; CHECK-NEXT:    madd x14, x14, x3, x11
-; CHECK-NEXT:    mov w28, w30
-; CHECK-NEXT:    mov w3, #-7680 // =0xffffe200
+; CHECK-NEXT:    lsl x23, x15, #1
+; CHECK-NEXT:    mov w28, w27
+; CHECK-NEXT:    madd x15, x15, x11, x12
+; CHECK-NEXT:    mov x11, #-1 // =0xffffffffffffffff
+; CHECK-NEXT:    mov w13, #-7680 // =0xffffe200
 ; CHECK-NEXT:    b .LBB0_36
 ; CHECK-NEXT:    .p2align 5, , 16
 ; CHECK-NEXT:  .LBB0_34: // %if.then466.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_36 Depth=5
 ; CHECK-NEXT:    ldr x28, [sp, #152] // 8-byte Reload
-; CHECK-NEXT:    ldr x3, [sp, #136] // 8-byte Reload
+; CHECK-NEXT:    ldr x13, [sp, #136] // 8-byte Reload
 ; CHECK-NEXT:    sxtb w4, w4
 ; CHECK-NEXT:    bic w4, w4, w4, asr #31
-; CHECK-NEXT:    str x3, [x28]
-; CHECK-NEXT:    mov w3, #-7680 // =0xffffe200
+; CHECK-NEXT:    str x13, [x28]
+; CHECK-NEXT:    mov w13, #-7680 // =0xffffe200
 ; CHECK-NEXT:  .LBB0_35: // %for.inc505.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_36 Depth=5
 ; CHECK-NEXT:    add x22, x22, #1
-; CHECK-NEXT:    add x27, x27, #1
+; CHECK-NEXT:    add x11, x11, #1
 ; CHECK-NEXT:    mov w28, wzr
-; CHECK-NEXT:    cmp x27, #0
+; CHECK-NEXT:    cmp x11, #0
 ; CHECK-NEXT:    b.hs .LBB0_9
 ; CHECK-NEXT:  .LBB0_36: // %for.body380.us
 ; CHECK-NEXT:    // Parent Loop BB0_4 Depth=1
@@ -358,23 +355,23 @@ define void @f(i1 %var_0, i16 %var_1, i64 %var_2, i8 %var_3, i16 %var_4, i1 %var
 ; CHECK-NEXT:    // Parent Loop BB0_8 Depth=3
 ; CHECK-NEXT:    // Parent Loop BB0_10 Depth=4
 ; CHECK-NEXT:    // => This Inner Loop Header: Depth=5
-; CHECK-NEXT:    mov w30, w28
+; CHECK-NEXT:    mov w27, w28
 ; CHECK-NEXT:    ldrh w28, [x23]
 ; CHECK-NEXT:    tst w0, #0x1
-; CHECK-NEXT:    strh w28, [x11]
-; CHECK-NEXT:    csel w28, w21, w3, ne
-; CHECK-NEXT:    str w28, [x20]
-; CHECK-NEXT:    cbz x15, .LBB0_35
+; CHECK-NEXT:    strh w28, [x12]
+; CHECK-NEXT:    csel w28, w3, w13, ne
+; CHECK-NEXT:    str w28, [x21]
+; CHECK-NEXT:    cbz x16, .LBB0_35
 ; CHECK-NEXT:  // %bb.37: // %if.then436.us
 ; CHECK-NEXT:    // in Loop: Header=BB0_36 Depth=5
-; CHECK-NEXT:    ldrh w28, [x14]
+; CHECK-NEXT:    ldrh w28, [x15]
 ; CHECK-NEXT:    cbnz w28, .LBB0_34
 ; CHECK-NEXT:  // %bb.38: // in Loop: Header=BB0_36 Depth=5
 ; CHECK-NEXT:    mov w4, wzr
 ; CHECK-NEXT:    b .LBB0_35
 ; CHECK-NEXT:  .LBB0_39: // %for.body41
 ; CHECK-NEXT:    strb wzr, [x4]
-; CHECK-NEXT:    strb wzr, [x14]
+; CHECK-NEXT:    strb wzr, [x15]
 ; CHECK-NEXT:  .LBB0_40: // %for.cond563.preheader
 ; CHECK-NEXT:    ldp x20, x19, [sp, #224] // 16-byte Folded Reload
 ; CHECK-NEXT:    ldp x22, x21, [sp, #208] // 16-byte Folded Reload
diff --git a/llvm/test/CodeGen/RISCV/O3-pipeline.ll b/llvm/test/CodeGen/RISCV/O3-pipeline.ll
index 149764ffedf9e..f91401760c12e 100644
--- a/llvm/test/CodeGen/RISCV/O3-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O3-pipeline.ll
@@ -121,6 +121,7 @@
 ; CHECK-NEXT:       Machine Trace Metrics 
 ; CHECK-NEXT:       Lazy Machine Block Frequency Analysis 
 ; CHECK-NEXT:       Machine InstCombiner 
+; CHECK-NEXT:       Sparse Live Variable Analysis
 ; CHECK-NEXT:       Machine Block Frequency Analysis
 ; CHECK-NEXT:       Early Machine Loop Invariant Code Motion
 ; CHECK-NEXT:       MachineDominator Tree Construction
@@ -171,6 +172,7 @@
 ; CHECK-NEXT:       Register Allocation Pass Scoring
 ; CHECK-NEXT:       Stack Slot Coloring
 ; CHECK-NEXT:       Machine Copy Propagation Pass
+; CHECK-NEXT:       Sparse Live Variable Analysis
 ; CHECK-NEXT:       Machine Loop Invariant Code Motion
 ; CHECK-NEXT:       RISC-V Redundant Copy Elimination
 ; CHECK-NEXT:       Remove Redundant DEBUG_VALUE analysis
diff --git a/llvm/test/CodeGen/RISCV/rvv/pr95865.ll b/llvm/test/CodeGen/RISCV/rvv/pr95865.ll
index 01d66b344ec2e..663db13596c31 100644
--- a/llvm/test/CodeGen/RISCV/rvv/pr95865.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/pr95865.ll
@@ -36,12 +36,15 @@ define i32 @main(i1 %arg.1, i64 %arg.2, i1 %arg.3, i64 %arg.4, i1 %arg.5, <vscal
 ; CHECK-NEXT:    .cfi_offset s10, -96
 ; CHECK-NEXT:    .cfi_offset s11, -104
 ; CHECK-NEXT:    li a6, 0
-; CHECK-NEXT:    li s2, 8
+; CHECK-NEXT:    li a7, 8
 ; CHECK-NEXT:    li t0, 12
 ; CHECK-NEXT:    li s0, 4
 ; CHECK-NEXT:    li t1, 20
+; CHECK-NEXT:    ld s2, 112(sp)
 ; CHECK-NEXT:    vsetivli zero, 8, e32, m2, ta, ma
 ; CHECK-NEXT:    vmv.v.i v8, 0
+; CHECK-NEXT:    andi s11, a0, 1
+; CHECK-NEXT:    andi s5, a2, 1
 ; CHECK-NEXT:    andi t3, a4, 1
 ; CHECK-NEXT:    li t2, 4
 ; CHECK-NEXT:  .LBB0_1: # %for.cond1.preheader.i
@@ -53,7 +56,7 @@ define i32 @main(i1 %arg.1, i64 %arg.2, i1 %arg.3, i64 %arg.4, i1 %arg.5, <vscal
 ; CHECK-NEXT:    mv t4, t1
 ; CHECK-NEXT:    mv t5, t2
 ; CHECK-NEXT:    mv t6, t0
-; CHECK-NEXT:    mv a7, s2
+; CHECK-NEXT:    mv s3, a7
 ; CHECK-NEXT:    mv s4, a6
 ; CHECK-NEXT:  .LBB0_2: # %for.cond5.preheader.i
 ; CHECK-NEXT:    # Parent Loop BB0_1 Depth=1
@@ -61,64 +64,62 @@ define i32 @main(i1 %arg.1, i64 %arg.2, i1 %arg.3, i64 %arg.4, i1 %arg.5, <vscal
 ; CHECK-NEXT:    # Child Loop BB0_3 Depth 3
 ; CHECK-NEXT:    # Child Loop BB0_4 Depth 4
 ; CHECK-NEXT:    # Child Loop BB0_5 Depth 5
-; CHECK-NEXT:    mv s5, t4
-; CHECK-NEXT:    mv s6, t5
-; CHECK-NEXT:    mv s7, t6
-; CHECK-NEXT:    mv s3, a7
-; CHECK-NEXT:    mv s9, s4
+; CHECK-NEXT:    mv s6, t4
+; CHECK-NEXT:    mv s7, t5
+; CHECK-NEXT:    mv s8, t6
+; CHECK-NEXT:    mv s9, s3
+; CHECK-NEXT:    mv s10, s4
 ; CHECK-NEXT:  .LBB0_3: # %for.cond9.preheader.i
 ; CHECK-NEXT:    # Parent Loop BB0_1 Depth=1
 ; CHECK-NEXT:    # Parent Loop BB0_2 Depth=2
 ; CHECK-NEXT:    # => This Loop Header: Depth=3
 ; CHECK-NEXT:    # Child Loop BB0_4 Depth 4
 ; CHECK-NEXT:    # Child Loop BB0_5 Depth 5
-; CHECK-NEXT:    mv s11, s5
-; CHECK-NEXT:    mv a3, s6
-; CHECK-NEXT:    mv ra, s7
-; CHECK-NEXT:    mv s8, s3
-; CHECK-NEXT:    mv s1, s9
+; CHECK-NEXT:    mv ra, s6
+; CHECK-NEXT:    mv a0, s7
+; CHECK-NEXT:    mv a3, s8
+; CHECK-NEXT:    mv a1, s9
+; CHECK-NEXT:    mv a4, s10
 ; CHECK-NEXT:  .LBB0_4: # %vector.ph.i
 ; CHECK-NEXT:    # Parent Loop BB0_1 Depth=1
 ; CHECK-NEXT:    # Parent Loop BB0_2 Depth=2
 ; CHECK-NEXT:    # Parent Loop BB0_3 Depth=3
 ; CHECK-NEXT:    # => This Loop Header: Depth=4
 ; CHECK-NEXT:    # Child Loop BB0_5 Depth 5
-; CHECK-NEXT:    li a1, 0
+; CHECK-NEXT:    li a2, 0
 ; CHECK-NEXT:  .LBB0_5: # %vector.body.i
 ; CHECK-NEXT:    # Parent Loop BB0_1 Depth=1
 ; CHECK-NEXT:    # Parent Loop BB0_2 Depth=2
 ; CHECK-NEXT:    # Parent Loop BB0_3 Depth=3
 ; CHECK-NEXT:    # Parent Loop BB0_4 Depth=4
 ; CHECK-NEXT:    # => This Inner Loop Header: Depth=5
-; CHECK-NEXT:    addi a5, a1, 4
-; CHECK-NEXT:    add a4, s8, a1
-; CHECK-NEXT:    add a1, a1, a3
-; CHECK-NEXT:    vse32.v v8, (a4), v0.t
-; CHECK-NEXT:    vse32.v v8, (a1), v0.t
-; CHECK-NEXT:    mv a1, a5
-; CHECK-NEXT:    bne a5, s0, .LBB0_5
+; CHECK-NEXT:    addi s1, a2, 4
+; CHECK-NEXT:    add a5, a1, a2
+; CHECK-NEXT:    add a2, a2, a0
+; CHECK-NEXT:    vse32.v v8, (a5), v0.t
+; CHECK-NEXT:    vse32.v v8, (a2), v0.t
+; CHECK-NEXT:    mv a2, s1
+; CHECK-NEXT:    bne s1, s0, .LBB0_5
 ; CHECK-NEXT:  # %bb.6: # %for.cond.cleanup15.i
 ; CHECK-NEXT:    # in Loop: Header=BB0_4 Depth=4
-; CHECK-NEXT:    addi s1, s1, 4
-; CHECK-NEXT:    addi s8, s8, 4
-; CHECK-NEXT:    addi ra, ra, 4
+; CHECK-NEXT:    addi a4, a4, 4
+; CHECK-NEXT:    addi a1, a1, 4
 ; CHECK-NEXT:    addi a3, a3, 4
-; CHECK-NEXT:    andi s10, a0, 1
-; CHECK-NEXT:    addi s11, s11, 4
-; CHECK-NEXT:    beqz s10, .LBB0_4
+; CHECK-NEXT:    addi a0, a0, 4
+; CHECK-NEXT:    addi ra, ra, 4
+; CHECK-NEXT:    beqz s11, .LBB0_4
 ; CHECK-NEXT:  # %bb.7: # %for.cond.cleanup11.i
 ; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=3
+; CHECK-NEXT:    addi s10, s10, 4
 ; CHECK-NEXT:    addi s9, s9, 4
-; CHECK-NEXT:    addi s3, s3, 4
+; CHECK-NEXT:    addi s8, s8, 4
 ; CHECK-NEXT:    addi s7, s7, 4
 ; CHECK-NEXT:    addi s6, s6, 4
-; CHECK-NEXT:    andi a1, a2, 1
-; CHECK-NEXT:    addi s5, s5, 4
-; CHECK-NEXT:    beqz a1, .LBB0_3
+; CHECK-NEXT:    beqz s5, .LBB0_3
 ; CHECK-NEXT:  # %bb.8: # %for.cond.cleanup7.i
 ; CHECK-NEXT:    # in Loop: Header=BB0_2 Depth=2
 ; CHECK-NEXT:    addi s4, s4, 4
-; CHECK-NEXT:    addi a7, a7, 4
+; CHECK-NEXT:    addi s3, s3, 4
 ; CHECK-NEXT:    addi t6, t6, 4
 ; CHECK-NEXT:    addi t5, t5, 4
 ; CHECK-NEXT:    addi t4, t4, 4
@@ -126,22 +127,21 @@ define i32 @main(i1 %arg.1, i64 %arg.2, i1 %arg.3, i64 %arg.4, i1 %arg.5, <vscal
 ; CHECK-NEXT:  # %bb.9: # %for.cond.cleanup3.i
 ; CHECK-NEXT:    # in Loop: Header=BB0_1 Depth=1
 ; CHECK-NEXT:    addi a6, a6, 4
-; CHECK-NEXT:    addi s2, s2, 4
+; CHECK-NEXT:    addi a7, a7, 4
 ; CHECK-NEXT:    addi t0, t0, 4
 ; CHECK-NEXT:    addi t2, t2, 4
 ; CHECK-NEXT:    addi t1, t1, 4
-; CHECK-NEXT:    beqz a1, .LBB0_1
+; CHECK-NEXT:    beqz s5, .LBB0_1
 ; CHECK-NEXT:  # %bb.10: # %l.exit
 ; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    jalr a0
-; CHECK-NEXT:    beqz s10, .LBB0_12
+; CHECK-NEXT:    beqz s11, .LBB0_12
 ; CHECK-NEXT:  .LBB0_11: # %for.body7.us.14
 ; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
 ; CHECK-NEXT:    j .LBB0_11
 ; CHECK-NEXT:  .LBB0_12: # %for.body7.us.19
 ; CHECK-NEXT:    vsetvli a0, zero, e32, m8, ta, ma
-; CHECK-NEXT:    ld a0, 112(sp)
-; CHECK-NEXT:    vmv.s.x v16, a0
+; CHECK-NEXT:    vmv.s.x v16, s2
 ; CHECK-NEXT:    vmv.v.i v8, 0
 ; CHECK-NEXT:    vsetivli zero, 2, e32, m1, tu, ma
 ; CHECK-NEXT:    vslideup.vi v8, v16, 1
diff --git a/llvm/test/CodeGen/RISCV/rvv/vxrm-insert-out-of-loop.ll b/llvm/test/CodeGen/RISCV/rvv/vxrm-insert-out-of-loop.ll
index 854d76c2d8544..d04838683e148 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vxrm-insert-out-of-loop.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vxrm-insert-out-of-loop.ll
@@ -173,38 +173,41 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
 ; RV64P670-NEXT:    .cfi_offset s4, -40
 ; RV64P670-NEXT:    addi s1, a7, -1
 ; RV64P670-NEXT:    add s0, a0, a6
+; RV64P670-NEXT:    add t5, a2, a6
 ; RV64P670-NEXT:    li t0, 0
-; RV64P670-NEXT:    li t1, 0
 ; RV64P670-NEXT:    zext.w s1, s1
+; RV64P670-NEXT:    li t1, 0
 ; RV64P670-NEXT:    mul t2, a1, s1
-; RV64P670-NEXT:    add t4, s0, t2
-; RV64P670-NEXT:    mul t2, a3, s1
-; RV64P670-NEXT:    add s0, a2, a6
-; RV64P670-NEXT:    mul s1, a5, s1
-; RV64P670-NEXT:    add t3, s0, t2
-; RV64P670-NEXT:    add s0, a4, a6
-; RV64P670-NEXT:    csrr t2, vlenb
-; RV64P670-NEXT:    add t5, s0, s1
+; RV64P670-NEXT:    mul t3, a3, s1
+; RV64P670-NEXT:    mul t4, a5, s1
+; RV64P670-NEXT:    add s1, a4, a6
+; RV64P670-NEXT:    add t6, s0, t2
+; RV64P670-NEXT:    add t3, t3, t5
+; RV64P670-NEXT:    add t4, t4, s1
+; RV64P670-NEXT:    csrr t5, vlenb
 ; RV64P670-NEXT:    sltu s1, a0, t3
-; RV64P670-NEXT:    sltu s0, a2, t4
-; RV64P670-NEXT:    slli t3, t2, 1
+; RV64P670-NEXT:    sltu s0, a2, t6
+; RV64P670-NEXT:    slli t2, t5, 1
+; RV64P670-NEXT:    slli t5, t5, 28
 ; RV64P670-NEXT:    and s0, s0, s1
 ; RV64P670-NEXT:    or s1, a1, a3
 ; RV64P670-NEXT:    srli s1, s1, 63
-; RV64P670-NEXT:    or t6, s0, s1
-; RV64P670-NEXT:    sltu s1, a0, t5
-; RV64P670-NEXT:    sltu s0, a4, t4
-; RV64P670-NEXT:    add t4, a0, a6
+; RV64P670-NEXT:    or t3, s0, s1
+; RV64P670-NEXT:    sltu s1, a0, t4
+; RV64P670-NEXT:    sltu s0, a4, t6
 ; RV64P670-NEXT:    and s0, s0, s1
 ; RV64P670-NEXT:    or s1, a1, a5
 ; RV64P670-NEXT:    srli s1, s1, 63
 ; RV64P670-NEXT:    or s0, s0, s1
 ; RV64P670-NEXT:    li s1, 32
-; RV64P670-NEXT:    maxu s1, t3, s1
-; RV64P670-NEXT:    or s0, t6, s0
+; RV64P670-NEXT:    maxu s1, t2, s1
+; RV64P670-NEXT:    or s0, t3, s0
+; RV64P670-NEXT:    add t3, a0, a6
 ; RV64P670-NEXT:    sltu s1, a6, s1
 ; RV64P670-NEXT:    or s0, s0, s1
-; RV64P670-NEXT:    andi t5, s0, 1
+; RV64P670-NEXT:    sub s1, t5, t2
+; RV64P670-NEXT:    andi t4, s0, 1
+; RV64P670-NEXT:    and t5, s1, a6
 ; RV64P670-NEXT:    j .LBB0_4
 ; RV64P670-NEXT:  .LBB0_3: # %for.cond1.for.cond.cleanup3_crit_edge.us
 ; RV64P670-NEXT:    # in Loop: Header=BB0_4 Depth=1
@@ -218,55 +221,53 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
 ; RV64P670-NEXT:    # =>This Loop Header: Depth=1
 ; RV64P670-NEXT:    # Child Loop BB0_7 Depth 2
 ; RV64P670-NEXT:    # Child Loop BB0_10 Depth 2
-; RV64P670-NEXT:    beqz t5, .LBB0_6
+; RV64P670-NEXT:    beqz t4, .LBB0_6
 ; RV64P670-NEXT:  # %bb.5: # in Loop: Header=BB0_4 Depth=1
-; RV64P670-NEXT:    li t6, 0
+; RV64P670-NEXT:    li s1, 0
 ; RV64P670-NEXT:    j .LBB0_9
 ; RV64P670-NEXT:  .LBB0_6: # %vector.ph
 ; RV64P670-NEXT:    # in Loop: Header=BB0_4 Depth=1
-; RV64P670-NEXT:    slli s1, t2, 28
-; RV64P670-NEXT:    mv s2, a2
-; RV64P670-NEXT:    mv s3, a4
-; RV64P670-NEXT:    mv s4, a0
-; RV64P670-NEXT:    sub s1, s1, t3
-; RV64P670-NEXT:    vsetvli s0, zero, e8, m2, ta, ma
-; RV64P670-NEXT:    and t6, s1, a6
-; RV64P670-NEXT:    mv s1, t6
+; RV64P670-NEXT:    mv t6, a2
+; RV64P670-NEXT:    mv s2, a4
+; RV64P670-NEXT:    mv s3, a0
+; RV64P670-NEXT:    mv s0, t5
+; RV64P670-NEXT:    vsetvli s1, zero, e8, m2, ta, ma
 ; RV64P670-NEXT:  .LBB0_7: # %vector.body
 ; RV64P670-NEXT:    # Parent Loop BB0_4 Depth=1
 ; RV64P670-NEXT:    # => This Inner Loop Header: Depth=2
-; RV64P670-NEXT:    vl2r.v v8, (s2)
-; RV64P670-NEXT:    sub s1, s1, t3
-; RV64P670-NEXT:    add s2, s2, t3
-; RV64P670-NEXT:    vl2r.v v10, (s3)
-; RV64P670-NEXT:    add s3, s3, t3
+; RV64P670-NEXT:    vl2r.v v8, (t6)
+; RV64P670-NEXT:    sub s0, s0, t2
+; RV64P670-NEXT:    add t6, t6, t2
+; RV64P670-NEXT:    vl2r.v v10, (s2)
+; RV64P670-NEXT:    add s2, s2, t2
 ; RV64P670-NEXT:    vaaddu.vv v8, v8, v10
-; RV64P670-NEXT:    vs2r.v v8, (s4)
-; RV64P670-NEXT:    add s4, s4, t3
-; RV64P670-NEXT:    bnez s1, .LBB0_7
+; RV64P670-NEXT:    vs2r.v v8, (s3)
+; RV64P670-NEXT:    add s3, s3, t2
+; RV64P670-NEXT:    bnez s0, .LBB0_7
 ; RV64P670-NEXT:  # %bb.8: # %middle.block
 ; RV64P670-NEXT:    # in Loop: Header=BB0_4 Depth=1
-; RV64P670-NEXT:    beq t6, a6, .LBB0_3
+; RV64P670-NEXT:    mv s1, t5
+; RV64P670-NEXT:    beq t5, a6, .LBB0_3
 ; RV64P670-NEXT:  .LBB0_9: # %for.body4.us.preheader
 ; RV64P670-NEXT:    # in Loop: Header=BB0_4 Depth=1
-; RV64P670-NEXT:    mul s2, a1, t0
-; RV64P670-NEXT:    add s1, a0, t6
-; RV64P670-NEXT:    add s4, a4, t6
-; RV64P670-NEXT:    add t6, t6, a2
-; RV64P670-NEXT:    add s2, s2, t4
+; RV64P670-NEXT:    mul t6, a1, t0
+; RV64P670-NEXT:    add s0, a0, s1
+; RV64P670-NEXT:    add s2, a4, s1
+; RV64P670-NEXT:    add s4, a2, s1
+; RV64P670-NEXT:    add t6, t6, t3
 ; RV64P670-NEXT:  .LBB0_10: # %for.body4.us
 ; RV64P670-NEXT:    # Parent Loop BB0_4 Depth=1
 ; RV64P670-NEXT:    # => This Inner Loop Header: Depth=2
-; RV64P670-NEXT:    lbu s3, 0(t6)
-; RV64P670-NEXT:    lbu s0, 0(s4)
+; RV64P670-NEXT:    lbu s3, 0(s4)
+; RV64P670-NEXT:    lbu s1, 0(s2)
+; RV64P670-NEXT:    addi s2, s2, 1
 ; RV64P670-NEXT:    addi s4, s4, 1
-; RV64P670-NEXT:    addi t6, t6, 1
-; RV64P670-NEXT:    add s0, s0, s3
-; RV64P670-NEXT:    addi s0, s0, 1
-; RV64P670-NEXT:    srli s0, s0, 1
-; RV64P670-NEXT:    sb s0, 0(s1)
+; RV64P670-NEXT:    add s1, s1, s3
 ; RV64P670-NEXT:    addi s1, s1, 1
-; RV64P670-NEXT:    bne s1, s2, .LBB0_10
+; RV64P670-NEXT:    srli s1, s1, 1
+; RV64P670-NEXT:    sb s1, 0(s0)
+; RV64P670-NEXT:    addi s0, s0, 1
+; RV64P670-NEXT:    bne s0, t6, .LBB0_10
 ; RV64P670-NEXT:    j .LBB0_3
 ; RV64P670-NEXT:  .LBB0_11:
 ; RV64P670-NEXT:    ld s0, 40(sp) # 8-byte Folded Reload
@@ -307,36 +308,39 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
 ; RV64X60-NEXT:    li t1, 0
 ; RV64X60-NEXT:    addi s1, a7, -1
 ; RV64X60-NEXT:    zext.w s1, s1
-; RV64X60-NEXT:    mul t3, a1, s1
+; RV64X60-NEXT:    mul t2, a1, s1
 ; RV64X60-NEXT:    mul t5, a3, s1
-; RV64X60-NEXT:    mul t4, a5, s1
+; RV64X60-NEXT:    mul t3, a5, s1
 ; RV64X60-NEXT:    add s1, a0, a6
-; RV64X60-NEXT:    csrr t2, vlenb
+; RV64X60-NEXT:    csrr t4, vlenb
 ; RV64X60-NEXT:    add s0, a2, a6
-; RV64X60-NEXT:    add s2, s1, t3
-; RV64X60-NEXT:    add t3, a4, a6
+; RV64X60-NEXT:    add s2, s1, t2
+; RV64X60-NEXT:    add t2, a4, a6
 ; RV64X60-NEXT:    add t5, t5, s0
 ; RV64X60-NEXT:    or t6, a1, a3
-; RV64X60-NEXT:    add t4, t4, t3
+; RV64X60-NEXT:    add t3, t3, t2
 ; RV64X60-NEXT:    sltu s0, a0, t5
 ; RV64X60-NEXT:    sltu s1, a2, s2
 ; RV64X60-NEXT:    and t5, s0, s1
-; RV64X60-NEXT:    slli t3, t2, 1
-; RV64X60-NEXT:    sltu t4, a0, t4
+; RV64X60-NEXT:    slli t2, t4, 1
+; RV64X60-NEXT:    sltu t3, a0, t3
 ; RV64X60-NEXT:    sltu s0, a4, s2
 ; RV64X60-NEXT:    srli s1, t6, 63
-; RV64X60-NEXT:    and s0, t4, s0
-; RV64X60-NEXT:    or t4, t5, s1
+; RV64X60-NEXT:    and s0, t3, s0
+; RV64X60-NEXT:    or t3, t5, s1
 ; RV64X60-NEXT:    or s1, a1, a5
 ; RV64X60-NEXT:    li t5, 32
 ; RV64X60-NEXT:    srli s1, s1, 63
 ; RV64X60-NEXT:    or s0, s0, s1
-; RV64X60-NEXT:    maxu s1, t3, t5
-; RV64X60-NEXT:    or s0, t4, s0
+; RV64X60-NEXT:    maxu s1, t2, t5
+; RV64X60-NEXT:    or s0, t3, s0
 ; RV64X60-NEXT:    sltu s1, a6, s1
+; RV64X60-NEXT:    add t3, a0, a6
+; RV64X60-NEXT:    slli t4, t4, 28
 ; RV64X60-NEXT:    or s0, s0, s1
-; RV64X60-NEXT:    add t4, a0, a6
-; RV64X60-NEXT:    andi t5, s0, 1
+; RV64X60-NEXT:    sub s1, t4, t2
+; RV64X60-NEXT:    andi t4, s0, 1
+; RV64X60-NEXT:    and t5, s1, a6
 ; RV64X60-NEXT:    j .LBB0_4
 ; RV64X60-NEXT:  .LBB0_3: # %for.cond1.for.cond.cleanup3_crit_edge.us
 ; RV64X60-NEXT:    # in Loop: Header=BB0_4 Depth=1
@@ -350,55 +354,53 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
 ; RV64X60-NEXT:    # =>This Loop Header: Depth=1
 ; RV64X60-NEXT:    # Child Loop BB0_7 Depth 2
 ; RV64X60-NEXT:    # Child Loop BB0_10 Depth 2
-; RV64X60-NEXT:    beqz t5, .LBB0_6
+; RV64X60-NEXT:    beqz t4, .LBB0_6
 ; RV64X60-NEXT:  # %bb.5: # in Loop: Header=BB0_4 Depth=1
-; RV64X60-NEXT:    li t6, 0
+; RV64X60-NEXT:    li s0, 0
 ; RV64X60-NEXT:    j .LBB0_9
 ; RV64X60-NEXT:  .LBB0_6: # %vector.ph
 ; RV64X60-NEXT:    # in Loop: Header=BB0_4 Depth=1
-; RV64X60-NEXT:    slli s1, t2, 28
-; RV64X60-NEXT:    sub s1, s1, t3
-; RV64X60-NEXT:    and t6, s1, a6
-; RV64X60-NEXT:    mv s2, a2
-; RV64X60-NEXT:    mv s3, a4
-; RV64X60-NEXT:    mv s4, a0
-; RV64X60-NEXT:    mv s1, t6
-; RV64X60-NEXT:    vsetvli s0, zero, e8, m2, ta, ma
+; RV64X60-NEXT:    mv t6, a2
+; RV64X60-NEXT:    mv s2, a4
+; RV64X60-NEXT:    mv s3, a0
+; RV64X60-NEXT:    mv s0, t5
+; RV64X60-NEXT:    vsetvli s1, zero, e8, m2, ta, ma
 ; RV64X60-NEXT:  .LBB0_7: # %vector.body
 ; RV64X60-NEXT:    # Parent Loop BB0_4 Depth=1
 ; RV64X60-NEXT:    # => This Inner Loop Header: Depth=2
-; RV64X60-NEXT:    vl2r.v v8, (s2)
-; RV64X60-NEXT:    vl2r.v v10, (s3)
+; RV64X60-NEXT:    vl2r.v v8, (t6)
+; RV64X60-NEXT:    vl2r.v v10, (s2)
 ; RV64X60-NEXT:    vaaddu.vv v8, v8, v10
-; RV64X60-NEXT:    sub s1, s1, t3
-; RV64X60-NEXT:    vs2r.v v8, (s4)
-; RV64X60-NEXT:    add s4, s4, t3
-; RV64X60-NEXT:    add s3, s3, t3
-; RV64X60-NEXT:    add s2, s2, t3
-; RV64X60-NEXT:    bnez s1, .LBB0_7
+; RV64X60-NEXT:    sub s0, s0, t2
+; RV64X60-NEXT:    vs2r.v v8, (s3)
+; RV64X60-NEXT:    add s3, s3, t2
+; RV64X60-NEXT:    add s2, s2, t2
+; RV64X60-NEXT:    add t6, t6, t2
+; RV64X60-NEXT:    bnez s0, .LBB0_7
 ; RV64X60-NEXT:  # %bb.8: # %middle.block
 ; RV64X60-NEXT:    # in Loop: Header=BB0_4 Depth=1
-; RV64X60-NEXT:    beq t6, a6, .LBB0_3
+; RV64X60-NEXT:    mv s0, t5
+; RV64X60-NEXT:    beq t5, a6, .LBB0_3
 ; RV64X60-NEXT:  .LBB0_9: # %for.body4.us.preheader
 ; RV64X60-NEXT:    # in Loop: Header=BB0_4 Depth=1
 ; RV64X60-NEXT:    mul s2, a1, t0
-; RV64X60-NEXT:    add s0, a0, t6
-; RV64X60-NEXT:    add s2, s2, t4
-; RV64X60-NEXT:    add s4, a4, t6
-; RV64X60-NEXT:    add t6, t6, a2
+; RV64X60-NEXT:    add t6, a0, s0
+; RV64X60-NEXT:    add s2, s2, t3
+; RV64X60-NEXT:    add s4, a4, s0
+; RV64X60-NEXT:    add s0, s0, a2
 ; RV64X60-NEXT:  .LBB0_10: # %for.body4.us
 ; RV64X60-NEXT:    # Parent Loop BB0_4 Depth=1
 ; RV64X60-NEXT:    # => This Inner Loop Header: Depth=2
-; RV64X60-NEXT:    lbu s3, 0(t6)
+; RV64X60-NEXT:    lbu s3, 0(s0)
 ; RV64X60-NEXT:    lbu s1, 0(s4)
 ; RV64X60-NEXT:    add s1, s1, s3
 ; RV64X60-NEXT:    addi s1, s1, 1
 ; RV64X60-NEXT:    srli s1, s1, 1
-; RV64X60-NEXT:    sb s1, 0(s0)
-; RV64X60-NEXT:    addi s0, s0, 1
-; RV64X60-NEXT:    addi s4, s4, 1
+; RV64X60-NEXT:    sb s1, 0(t6)
 ; RV64X60-NEXT:    addi t6, t6, 1
-; RV64X60-NEXT:    bne s0, s2, .LBB0_10
+; RV64X60-NEXT:    addi s4, s4, 1
+; RV64X60-NEXT:    addi s0, s0, 1
+; RV64X60-NEXT:    bne t6, s2, .LBB0_10
 ; RV64X60-NEXT:    j .LBB0_3
 ; RV64X60-NEXT:  .LBB0_11:
 ; RV64X60-NEXT:    ld s4, 8(sp) # 8-byte Folded Reload
@@ -434,28 +436,28 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
 ; RV64-NEXT:    .cfi_offset s2, -24
 ; RV64-NEXT:    .cfi_offset s3, -32
 ; RV64-NEXT:    .cfi_offset s4, -40
-; RV64-NEXT:    addi t1, a7, -1
+; RV64-NEXT:    addi t0, a7, -1
 ; RV64-NEXT:    add t5, a0, a6
 ; RV64-NEXT:    add s0, a2, a6
 ; RV64-NEXT:    add t6, a4, a6
-; RV64-NEXT:    csrr t0, vlenb
-; RV64-NEXT:    li t2, 32
-; RV64-NEXT:    slli t1, t1, 32
-; RV64-NEXT:    srli t3, t1, 32
-; RV64-NEXT:    mul t1, a1, t3
-; RV64-NEXT:    add t5, t5, t1
-; RV64-NEXT:    mul t1, a3, t3
-; RV64-NEXT:    add s0, s0, t1
-; RV64-NEXT:    slli t1, t0, 1
-; RV64-NEXT:    mul t3, a5, t3
-; RV64-NEXT:    add t6, t6, t3
-; RV64-NEXT:    mv t4, t1
-; RV64-NEXT:    bltu t2, t1, .LBB0_4
+; RV64-NEXT:    csrr t4, vlenb
+; RV64-NEXT:    li t1, 32
+; RV64-NEXT:    slli t0, t0, 32
+; RV64-NEXT:    srli t2, t0, 32
+; RV64-NEXT:    mul t0, a1, t2
+; RV64-NEXT:    add t5, t5, t0
+; RV64-NEXT:    mul t0, a3, t2
+; RV64-NEXT:    add s0, s0, t0
+; RV64-NEXT:    slli t0, t4, 1
+; RV64-NEXT:    mul t2, a5, t2
+; RV64-NEXT:    add t6, t6, t2
+; RV64-NEXT:    mv t3, t0
+; RV64-NEXT:    bltu t1, t0, .LBB0_4
 ; RV64-NEXT:  # %bb.3: # %for.cond1.preheader.us.preheader
-; RV64-NEXT:    li t4, 32
+; RV64-NEXT:    li t3, 32
 ; RV64-NEXT:  .LBB0_4: # %for.cond1.preheader.us.preheader
+; RV64-NEXT:    li t1, 0
 ; RV64-NEXT:    li t2, 0
-; RV64-NEXT:    li t3, 0
 ; RV64-NEXT:    sltu s0, a0, s0
 ; RV64-NEXT:    sltu s1, a2, t5
 ; RV64-NEXT:    and s0, s0, s1
@@ -468,11 +470,14 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
 ; RV64-NEXT:    or s0, a1, a5
 ; RV64-NEXT:    srli s0, s0, 63
 ; RV64-NEXT:    or t5, t5, s0
-; RV64-NEXT:    sltu s0, a6, t4
+; RV64-NEXT:    sltu s0, a6, t3
 ; RV64-NEXT:    or t5, t6, t5
-; RV64-NEXT:    add t4, a0, a6
-; RV64-NEXT:    or t5, s0, t5
-; RV64-NEXT:    andi t5, t5, 1
+; RV64-NEXT:    add t3, a0, a6
+; RV64-NEXT:    slli t4, t4, 28
+; RV64-NEXT:    sub t6, t4, t0
+; RV64-NEXT:    or t4, s0, t5
+; RV64-NEXT:    andi t4, t4, 1
+; RV64-NEXT:    and t5, t6, a6
 ; RV64-NEXT:    csrwi vxrm, 0
 ; RV64-NEXT:    j .LBB0_6
 ; RV64-NEXT:  .LBB0_5: # %for.cond1.for.cond.cleanup3_crit_edge.us
@@ -480,62 +485,60 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
 ; RV64-NEXT:    add a0, a0, a1
 ; RV64-NEXT:    add a2, a2, a3
 ; RV64-NEXT:    add a4, a4, a5
-; RV64-NEXT:    addiw t3, t3, 1
-; RV64-NEXT:    addi t2, t2, 1
-; RV64-NEXT:    beq t3, a7, .LBB0_13
+; RV64-NEXT:    addiw t2, t2, 1
+; RV64-NEXT:    addi t1, t1, 1
+; RV64-NEXT:    beq t2, a7, .LBB0_13
 ; RV64-NEXT:  .LBB0_6: # %for.cond1.preheader.us
 ; RV64-NEXT:    # =>This Loop Header: Depth=1
 ; RV64-NEXT:    # Child Loop BB0_9 Depth 2
 ; RV64-NEXT:    # Child Loop BB0_12 Depth 2
-; RV64-NEXT:    beqz t5, .LBB0_8
+; RV64-NEXT:    beqz t4, .LBB0_8
 ; RV64-NEXT:  # %bb.7: # in Loop: Header=BB0_6 Depth=1
-; RV64-NEXT:    li t6, 0
+; RV64-NEXT:    li s2, 0
 ; RV64-NEXT:    j .LBB0_11
 ; RV64-NEXT:  .LBB0_8: # %vector.ph
 ; RV64-NEXT:    # in Loop: Header=BB0_6 Depth=1
-; RV64-NEXT:    slli t6, t0, 28
-; RV64-NEXT:    sub t6, t6, t1
-; RV64-NEXT:    and t6, t6, a6
-; RV64-NEXT:    mv s0, a2
-; RV64-NEXT:    mv s1, a4
-; RV64-NEXT:    mv s2, a0
-; RV64-NEXT:    mv s3, t6
-; RV64-NEXT:    vsetvli s4, zero, e8, m2, ta, ma
+; RV64-NEXT:    mv t6, a2
+; RV64-NEXT:    mv s0, a4
+; RV64-NEXT:    mv s1, a0
+; RV64-NEXT:    mv s2, t5
+; RV64-NEXT:    vsetvli s3, zero, e8, m2, ta, ma
 ; RV64-NEXT:  .LBB0_9: # %vector.body
 ; RV64-NEXT:    # Parent Loop BB0_6 Depth=1
 ; RV64-NEXT:    # => This Inner Loop Header: Depth=2
-; RV64-NEXT:    vl2r.v v8, (s0)
-; RV64-NEXT:    vl2r.v v10, (s1)
-; RV64-NEXT:    sub s3, s3, t1
-; RV64-NEXT:    add s1, s1, t1
+; RV64-NEXT:    vl2r.v v8, (t6)
+; RV64-NEXT:    vl2r.v v10, (s0)
+; RV64-NEXT:    sub s2, s2, t0
+; RV64-NEXT:    add s0, s0, t0
 ; RV64-NEXT:    vaaddu.vv v8, v8, v10
-; RV64-NEXT:    vs2r.v v8, (s2)
-; RV64-NEXT:    add s2, s2, t1
-; RV64-NEXT:    add s0, s0, t1
-; RV64-NEXT:    bnez s3, .LBB0_9
+; RV64-NEXT:    vs2r.v v8, (s1)
+; RV64-NEXT:    add s1, s1, t0
+; RV64-NEXT:    add t6, t6, t0
+; RV64-NEXT:    bnez s2, .LBB0_9
 ; RV64-NEXT:  # %bb.10: # %middle.block
 ; RV64-NEXT:    # in Loop: Header=BB0_6 Depth=1
-; RV64-NEXT:    beq t6, a6, .LBB0_5
+; RV64-NEXT:    mv s2, t5
+; RV64-NEXT:    beq t5, a6, .LBB0_5
 ; RV64-NEXT:  .LBB0_11: # %for.body4.us.preheader
 ; RV64-NEXT:    # in Loop: Header=BB0_6 Depth=1
-; RV64-NEXT:    mul s2, a1, t2
-; RV64-NEXT:    add s0, a0, t6
-; RV64-NEXT:    add s1, a4, t6
-; RV64-NEXT:    add s2, t4, s2
-; RV64-NEXT:    add t6, a2, t6
+; RV64-NEXT:    mul s1, a1, t1
+; RV64-NEXT:    add t6, a0, s2
+; RV64-NEXT:    add s0, a4, s2
+; RV64-NEXT:    add s1, t3, s1
+; RV64-NEXT:    add s2, a2, s2
 ; RV64-NEXT:  .LBB0_12: # %for.body4.us
 ; RV64-NEXT:    # Parent Loop BB0_6 Depth=1
 ; RV64-NEXT:    # => This Inner Loop Header: Depth=2
-; RV64-NEXT:    lbu s3, 0(t6)
-; RV64-NEXT:    lbu s4, 0(s1)
+; RV64-NEXT:    lbu s3, 0(s2)
+; RV64-NEXT:    lbu s4, 0(s0)
 ; RV64-NEXT:    add s3, s3, s4
 ; RV64-NEXT:    addi s3, s3, 1
 ; RV64-NEXT:    srli s3, s3, 1
-; RV64-NEXT:    sb s3, 0(s0)
-; RV64-NEXT:    addi s0, s0, 1
-; RV64-NEXT:    addi s1, s1, 1
+; RV64-NEXT:    sb s3, 0(t6)
 ; RV64-NEXT:    addi t6, t6, 1
-; RV64-NEXT:    bne s0, s2, .LBB0_12
+; RV64-NEXT:    addi s0, s0, 1
+; RV64-NEXT:    addi s2, s2, 1
+; RV64-NEXT:    bne t6, s1, .LBB0_12
 ; RV64-NEXT:    j .LBB0_5
 ; RV64-NEXT:  .LBB0_13:
 ; RV64-NEXT:    ld s0, 40(sp) # 8-byte Folded Reload
diff --git a/llvm/test/CodeGen/X86/opt-pipeline.ll b/llvm/test/CodeGen/X86/opt-pipeline.ll
index 24390f2d852d3..3bf5937f75aea 100644
--- a/llvm/test/CodeGen/X86/opt-pipeline.ll
+++ b/llvm/test/CodeGen/X86/opt-pipeline.ll
@@ -107,6 +107,7 @@
 ; CHECK-NEXT:       Lazy Machine Block Frequency Analysis
 ; CHECK-NEXT:       Machine InstCombiner
 ; CHECK-NEXT:       X86 cmov Conversion
+; CHECK-NEXT:       Sparse Live Variable Analysis
 ; CHECK-NEXT:       MachineDominator Tree Construction
 ; CHECK-NEXT:       Machine Natural Loop Construction
 ; CHECK-NEXT:       Machine Block Frequency Analysis
@@ -160,6 +161,7 @@
 ; CHECK-NEXT:       Register Allocation Pass Scoring
 ; CHECK-NEXT:       Stack Slot Coloring
 ; CHECK-NEXT:       Machine Copy Propagation Pass
+; CHECK-NEXT:       Sparse Live Variable Analysis
 ; CHECK-NEXT:       Machine Loop Invariant Code Motion
 ; CHECK-NEXT:       X86 Lower Tile Copy
 ; CHECK-NEXT:       Bundle Machine CFG Edges
diff --git a/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp b/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
index e62a4af2b14a2..4b938ab7c0531 100644
--- a/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
+++ b/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
@@ -110,4 +110,59 @@ TEST(SparseLiveVariablesTest, APITests) {
   EXPECT_TRUE(MBB->livein_empty());
 }
 
+TEST(SparseLiveVariablesTest, IncrementalLivenessUpdates) {
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
+  auto MBB1 = MF->CreateMachineBasicBlock();
+  auto MBB2 = MF->CreateMachineBasicBlock();
+  MF->push_back(MBB1);
+  MF->push_back(MBB2);
+  MBB1->addSuccessor(MBB2);
+
+  MCInstrDesc MCID = {100, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+
+  MCRegisterClass MRC{
+      0, 0, 0, 0, 0, 0, 0, 0, /*Allocatable=*/true, /*BaseClass=*/true};
+  TargetRegisterClass RC{&MRC, 0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0};
+  MachineRegisterInfo &MRI = MF->getRegInfo();
+
+  Register Reg0 = MRI.createVirtualRegister(&RC);
+
+  // MI1 in MBB1: %0 = OP
+  MachineInstr *MI1 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI1->addOperand(*MF, MachineOperand::CreateReg(Reg0, /*isDef*/ true));
+  MBB1->insert(MBB1->end(), MI1);
+
+  // Run SparseLiveVariables analysis
+  SparseLiveVariables LV;
+  LV.runOnMachineFunction(*MF);
+
+  // Initially Reg0 is NOT live-out of MBB1 and NOT live-in to MBB2
+  EXPECT_FALSE(LV.getLiveOutSet(MBB1).test(Reg0.id()));
+  EXPECT_FALSE(LV.getLiveInSet(MBB2).test(Reg0.id()));
+
+  // Now, dynamically add a use of Reg0 in MBB2!
+  MachineInstr *MI2 = MF->CreateMachineInstr(MCID, DebugLoc());
+  Register Reg1 = MRI.createVirtualRegister(&RC);
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg1, /*isDef*/ true));
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg0, /*isDef*/ false));
+  MBB2->insert(MBB2->end(), MI2);
+
+  // Inform LV to incrementally update based on MI2
+  LV.addInstruction(*MI2, MBB2);
+
+  // Reg0 should now cleanly flow from MBB1 to MBB2
+  EXPECT_TRUE(LV.getLiveOutSet(MBB1).test(Reg0.id()));
+  EXPECT_TRUE(LV.getLiveInSet(MBB2).test(Reg0.id()));
+
+  // Now dynamically remove MI2 and update
+  LV.removeInstruction(*MI2);
+  MBB2->erase(MI2);
+
+  // The phantom liveness should disappear cleanly!
+  EXPECT_FALSE(LV.getLiveOutSet(MBB1).test(Reg0.id()));
+  EXPECT_FALSE(LV.getLiveInSet(MBB2).test(Reg0.id()));
+}
+
 } // end namespace

>From 1b5772e0c9cc5ff8ce5174ced2fd4db679331449 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sat, 18 Apr 2026 23:26:10 -0700
Subject: [PATCH 27/32] clang-format

---
 .../llvm/CodeGen/SparseLiveVariables.h        |  12 +
 llvm/lib/CodeGen/SparseLiveVariables.cpp      | 294 ++++++++++--------
 2 files changed, 177 insertions(+), 129 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/SparseLiveVariables.h b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
index 264a96283a973..2e15278022f53 100644
--- a/llvm/include/llvm/CodeGen/SparseLiveVariables.h
+++ b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
@@ -205,6 +205,18 @@ class SparseLiveVariables : public MachineFunctionPass {
 private:
   const MachineRegisterInfo *MRI;
   const TargetRegisterInfo *TRI;
+
+  void propagateGrowth(Register Reg, MachineBasicBlock *StartBB,
+                       MachineInstr *IgnoreMI = nullptr);
+  void propagateShrinkage(Register Reg, MachineBasicBlock *StartBB,
+                          MachineInstr *IgnoreMI = nullptr);
+
+  bool evaluateLiveIn(Register Reg, MachineBasicBlock *MBB,
+                      MachineInstr *IgnoreMI = nullptr) const;
+  bool isLiveOut(Register Reg, MachineBasicBlock *MBB,
+                 MachineInstr *IgnoreMI = nullptr) const;
+  void reevaluateLiveIn(Register Reg, MachineBasicBlock *MBB,
+                        MachineInstr *IgnoreMI = nullptr);
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/CodeGen/SparseLiveVariables.cpp b/llvm/lib/CodeGen/SparseLiveVariables.cpp
index d6532fc8de116..214da2e122cf2 100644
--- a/llvm/lib/CodeGen/SparseLiveVariables.cpp
+++ b/llvm/lib/CodeGen/SparseLiveVariables.cpp
@@ -210,7 +210,8 @@ void SparseLiveVariables::updateKillFlags(MachineFunction &MF) const {
   }
 }
 
-void SparseLiveVariables::recomputeRegisterLiveness(Register Reg, MachineInstr *IgnoreMI) {
+void SparseLiveVariables::recomputeRegisterLiveness(Register Reg,
+                                                    MachineInstr *IgnoreMI) {
   if (!Reg.isVirtual())
     return;
 
@@ -230,9 +231,11 @@ void SparseLiveVariables::recomputeRegisterLiveness(Register Reg, MachineInstr *
     MachineBasicBlock *MBB = UseMI.getParent();
 
     if (UseMI.isPHI()) {
-      // For PHI nodes, the register is live-out of the corresponding predecessor
+      // For PHI nodes, the register is live-out of the corresponding
+      // predecessor
       for (unsigned i = 1; i < UseMI.getNumOperands(); i += 2) {
-        if (UseMI.getOperand(i).isReg() && UseMI.getOperand(i).getReg() == Reg) {
+        if (UseMI.getOperand(i).isReg() &&
+            UseMI.getOperand(i).getReg() == Reg) {
           MachineBasicBlock *Pred = UseMI.getOperand(i + 1).getMBB();
           auto PredIt = BlockLiveness.find(Pred);
           if (PredIt != BlockLiveness.end()) {
@@ -301,168 +304,201 @@ void SparseLiveVariables::recomputeRegisterLiveness(Register Reg, MachineInstr *
   }
 }
 
-void SparseLiveVariables::addInstruction(MachineInstr &MI, MachineBasicBlock *MBB) {
-  if (!MBB)
-    MBB = MI.getParent();
-
-  for (const MachineOperand &MO : MI.operands()) {
-    if (!MO.isReg() || !MO.getReg().isVirtual())
+bool SparseLiveVariables::evaluateLiveIn(Register Reg, MachineBasicBlock *MBB,
+                                         MachineInstr *IgnoreMI) const {
+  for (const MachineInstr &BlockMI : *MBB) {
+    if (&BlockMI == IgnoreMI)
+      continue;
+    if (BlockMI.isPHI()) {
+      if (BlockMI.definesRegister(Reg, TRI))
+        return false;
       continue;
+    }
+    if (BlockMI.readsRegister(Reg, TRI))
+      return true;
+    if (BlockMI.definesRegister(Reg, TRI))
+      return false;
+  }
+  auto It = BlockLiveness.find(MBB);
+  if (It != BlockLiveness.end())
+    return It->second.LiveOut.test(Reg.id());
+  return false;
+}
 
-    Register Reg = MO.getReg();
+bool SparseLiveVariables::isLiveOut(Register Reg, MachineBasicBlock *MBB,
+                                    MachineInstr *IgnoreMI) const {
+  for (MachineBasicBlock *Succ : MBB->successors()) {
+    auto SuccIt = BlockLiveness.find(Succ);
+    if (SuccIt != BlockLiveness.end() && SuccIt->second.LiveIn.test(Reg.id()))
+      return true;
 
-    auto PropagateGrowth = [&](MachineBasicBlock *StartBB) {
-      SmallVector<MachineBasicBlock *, 8> WorkList;
-      WorkList.push_back(StartBB);
+    for (const MachineInstr &OtherPHI : *Succ) {
+      if (!OtherPHI.isPHI())
+        break;
+      if (&OtherPHI == IgnoreMI)
+        continue;
+      for (unsigned i = 1; i < OtherPHI.getNumOperands(); i += 2) {
+        if (OtherPHI.getOperand(i).isReg() &&
+            OtherPHI.getOperand(i).getReg() == Reg &&
+            OtherPHI.getOperand(i + 1).getMBB() == MBB) {
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
 
-      while (!WorkList.empty()) {
-        MachineBasicBlock *Curr = WorkList.pop_back_val();
-        for (MachineBasicBlock *Pred : Curr->predecessors()) {
-          auto PredIt = BlockLiveness.find(Pred);
-          if (PredIt == BlockLiveness.end())
-            continue;
+void SparseLiveVariables::reevaluateLiveIn(Register Reg, MachineBasicBlock *MBB,
+                                           MachineInstr *IgnoreMI) {
+  auto It = BlockLiveness.find(MBB);
+  if (It == BlockLiveness.end())
+    return;
 
-          if (!PredIt->second.LiveOut.test(Reg.id())) {
-            PredIt->second.LiveOut.set(Reg.id());
+  bool OldLiveIn = It->second.LiveIn.test(Reg.id());
+  bool NewLiveIn = evaluateLiveIn(Reg, MBB, IgnoreMI);
 
-            bool PredDef = false;
-            for (const MachineInstr &PredMI : llvm::reverse(*Pred)) {
-              if (PredMI.definesRegister(Reg, TRI)) {
-                PredDef = true;
-                break;
-              }
-            }
+  if (OldLiveIn != NewLiveIn) {
+    if (NewLiveIn) {
+      It->second.LiveIn.set(Reg.id());
+      propagateGrowth(Reg, MBB, IgnoreMI);
+    } else {
+      It->second.LiveIn.reset(Reg.id());
+      propagateShrinkage(Reg, MBB, IgnoreMI);
+    }
+  }
+}
 
-            if (!PredDef && !PredIt->second.LiveIn.test(Reg.id())) {
-              PredIt->second.LiveIn.set(Reg.id());
-              WorkList.push_back(Pred);
-            }
+void SparseLiveVariables::propagateGrowth(Register Reg,
+                                          MachineBasicBlock *StartBB,
+                                          MachineInstr *IgnoreMI) {
+  SmallVector<MachineBasicBlock *, 8> WorkList;
+  WorkList.push_back(StartBB);
+
+  while (!WorkList.empty()) {
+    MachineBasicBlock *Curr = WorkList.pop_back_val();
+    for (MachineBasicBlock *Pred : Curr->predecessors()) {
+      auto PredIt = BlockLiveness.find(Pred);
+      if (PredIt == BlockLiveness.end())
+        continue;
+
+      if (!PredIt->second.LiveOut.test(Reg.id())) {
+        PredIt->second.LiveOut.set(Reg.id());
+
+        if (!PredIt->second.LiveIn.test(Reg.id())) {
+          if (evaluateLiveIn(Reg, Pred, IgnoreMI)) {
+            PredIt->second.LiveIn.set(Reg.id());
+            WorkList.push_back(Pred);
           }
         }
       }
-    };
-
-    if (MO.isUse()) {
-      if (MI.isPHI()) {
-        MachineBasicBlock *Pred = nullptr;
-        for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
-          if (&MI.getOperand(i) == &MO) {
-            Pred = MI.getOperand(i + 1).getMBB();
-            break;
-          }
-        }
+    }
+  }
+}
 
-        if (Pred) {
-          auto PredIt = BlockLiveness.find(Pred);
-          if (PredIt != BlockLiveness.end() && !PredIt->second.LiveOut.test(Reg.id())) {
-            PredIt->second.LiveOut.set(Reg.id());
-
-            bool PredDef = false;
-            for (const MachineInstr &PredMI : llvm::reverse(*Pred)) {
-              if (PredMI.definesRegister(Reg, TRI)) {
-                PredDef = true;
-                break;
-              }
-            }
+void SparseLiveVariables::propagateShrinkage(Register Reg,
+                                             MachineBasicBlock *StartBB,
+                                             MachineInstr *IgnoreMI) {
+  SmallVector<MachineBasicBlock *, 8> WorkList;
+  WorkList.push_back(StartBB);
 
-            if (!PredDef && !PredIt->second.LiveIn.test(Reg.id())) {
-              PredIt->second.LiveIn.set(Reg.id());
-              PropagateGrowth(Pred);
-            }
-          }
-        }
+  while (!WorkList.empty()) {
+    MachineBasicBlock *Curr = WorkList.pop_back_val();
+    for (MachineBasicBlock *Pred : Curr->predecessors()) {
+      auto PredIt = BlockLiveness.find(Pred);
+      if (PredIt == BlockLiveness.end())
         continue;
-      }
 
-      if (BlockLiveness[MBB].LiveIn.test(Reg.id()))
+      if (!PredIt->second.LiveOut.test(Reg.id()))
         continue;
 
-      bool FoundDef = false;
-      for (auto I = MachineBasicBlock::reverse_iterator(&MI), E = MBB->rend(); I != E; ++I) {
-        if (I->definesRegister(Reg, TRI)) {
-          FoundDef = true;
-          break;
+      if (!isLiveOut(Reg, Pred, IgnoreMI)) {
+        PredIt->second.LiveOut.reset(Reg.id());
+
+        if (PredIt->second.LiveIn.test(Reg.id())) {
+          if (!evaluateLiveIn(Reg, Pred, IgnoreMI)) {
+            PredIt->second.LiveIn.reset(Reg.id());
+            WorkList.push_back(Pred);
+          }
         }
       }
+    }
+  }
+}
 
-      if (!FoundDef) {
-        BlockLiveness[MBB].LiveIn.set(Reg.id());
-        PropagateGrowth(MBB);
-      }
-    } else if (MO.isDef()) {
-      if (!BlockLiveness[MBB].LiveIn.test(Reg.id()))
-        continue;
+void SparseLiveVariables::addInstruction(MachineInstr &MI,
+                                         MachineBasicBlock *MBB) {
+  if (!MBB)
+    MBB = MI.getParent();
 
-      bool HasUseAbove = false;
-      for (auto I = MachineBasicBlock::reverse_iterator(&MI), E = MBB->rend(); I != E; ++I) {
-        if (I->readsRegister(Reg, TRI)) {
-          HasUseAbove = true;
+  for (const MachineOperand &MO : MI.operands()) {
+    if (!MO.isReg() || !MO.getReg().isVirtual())
+      continue;
+
+    Register Reg = MO.getReg();
+
+    if (MO.isUse() && MI.isPHI()) {
+      MachineBasicBlock *Pred = nullptr;
+      for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
+        if (&MI.getOperand(i) == &MO) {
+          Pred = MI.getOperand(i + 1).getMBB();
           break;
         }
       }
 
-      if (!HasUseAbove) {
-        BlockLiveness[MBB].LiveIn.reset(Reg.id());
-
-        SmallVector<MachineBasicBlock *, 8> WorkList;
-        WorkList.push_back(MBB);
-
-        while (!WorkList.empty()) {
-          MachineBasicBlock *Curr = WorkList.pop_back_val();
-          for (MachineBasicBlock *Pred : Curr->predecessors()) {
-            auto PredIt = BlockLiveness.find(Pred);
-            if (PredIt == BlockLiveness.end())
-              continue;
-
-            if (!PredIt->second.LiveOut.test(Reg.id()))
-              continue;
-
-            bool StillLiveOut = false;
-            for (MachineBasicBlock *Succ : Pred->successors()) {
-              auto SuccIt = BlockLiveness.find(Succ);
-              if (SuccIt != BlockLiveness.end() && SuccIt->second.LiveIn.test(Reg.id())) {
-                StillLiveOut = true;
-                break;
-              }
-            }
-
-            if (!StillLiveOut) {
-              PredIt->second.LiveOut.reset(Reg.id());
-
-              if (PredIt->second.LiveIn.test(Reg.id())) {
-                bool HasUse = false;
-                for (const MachineInstr &PredMI : *Pred) {
-                  if (PredMI.readsRegister(Reg, TRI)) {
-                    HasUse = true;
-                    break;
-                  }
-                  if (PredMI.definesRegister(Reg, TRI)) {
-                    break;
-                  }
-                }
-
-                if (!HasUse) {
-                  PredIt->second.LiveIn.reset(Reg.id());
-                  WorkList.push_back(Pred);
-                }
-              }
-            }
-          }
+      if (Pred) {
+        auto PredIt = BlockLiveness.find(Pred);
+        if (PredIt != BlockLiveness.end() &&
+            !PredIt->second.LiveOut.test(Reg.id())) {
+          PredIt->second.LiveOut.set(Reg.id());
+          reevaluateLiveIn(Reg, Pred);
         }
       }
+      continue;
     }
+
+    reevaluateLiveIn(Reg, MBB);
   }
 }
 
 void SparseLiveVariables::removeInstruction(MachineInstr &MI) {
+  MachineBasicBlock *MBB = MI.getParent();
+
   for (const MachineOperand &MO : MI.operands()) {
-    if (MO.isReg() && MO.getReg().isVirtual()) {
-      recomputeRegisterLiveness(MO.getReg(), &MI);
+    if (!MO.isReg() || !MO.getReg().isVirtual())
+      continue;
+
+    Register Reg = MO.getReg();
+
+    if (MO.isUse() && MI.isPHI()) {
+      MachineBasicBlock *Pred = nullptr;
+      for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
+        if (&MI.getOperand(i) == &MO) {
+          Pred = MI.getOperand(i + 1).getMBB();
+          break;
+        }
+      }
+
+      if (Pred) {
+        auto PredIt = BlockLiveness.find(Pred);
+        if (PredIt != BlockLiveness.end() &&
+            PredIt->second.LiveOut.test(Reg.id())) {
+          if (!isLiveOut(Reg, Pred, &MI)) {
+            PredIt->second.LiveOut.reset(Reg.id());
+            reevaluateLiveIn(Reg, Pred, &MI);
+          }
+        }
+      }
+      continue;
     }
+
+    reevaluateLiveIn(Reg, MBB, &MI);
   }
 }
 
-void SparseLiveVariables::handleMove(MachineInstr &MI, MachineBasicBlock * /*OldBB*/, MachineBasicBlock * /*NewBB*/) {
+void SparseLiveVariables::handleMove(MachineInstr &MI,
+                                     MachineBasicBlock * /*OldBB*/,
+                                     MachineBasicBlock * /*NewBB*/) {
   for (const MachineOperand &MO : MI.operands()) {
     if (MO.isReg() && MO.getReg().isVirtual()) {
       recomputeRegisterLiveness(MO.getReg());

>From b6830d71d27199542337e410004bc22daea81066 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Sun, 19 Apr 2026 00:30:05 -0700
Subject: [PATCH 28/32] [RISCV] Add MachineLICM test for issue 166141

---
 .../CodeGen/RISCV/machinelicm-issue-166141.ll | 114 ++++++++++++++++++
 1 file changed, 114 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/machinelicm-issue-166141.ll

diff --git a/llvm/test/CodeGen/RISCV/machinelicm-issue-166141.ll b/llvm/test/CodeGen/RISCV/machinelicm-issue-166141.ll
new file mode 100644
index 0000000000000..1195e251d96d0
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/machinelicm-issue-166141.ll
@@ -0,0 +1,114 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv64 -mattr=+d < %s | FileCheck %s
+
+define void @f(ptr %p) {
+; CHECK-LABEL: f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    lui a1, %hi(.LCPI0_0)
+; CHECK-NEXT:    fld fa5, %lo(.LCPI0_0)(a1)
+; CHECK-NEXT:    lui a1, 2
+; CHECK-NEXT:    add a1, a0, a1
+; CHECK-NEXT:    fmv.d.x fa4, zero
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_1: # %latch
+; CHECK-NEXT:    # in Loop: Header=BB0_2 Depth=1
+; CHECK-NEXT:    addi a0, a0, 8
+; CHECK-NEXT:    beq a0, a1, .LBB0_4
+; CHECK-NEXT:  .LBB0_2: # %loop
+; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    fld fa3, 0(a0)
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    fmul.d fa3, fa3, fa3
+; CHECK-NEXT:    feq.d a2, fa3, fa4
+; CHECK-NEXT:    bnez a2, .LBB0_1
+; CHECK-NEXT:  # %bb.3: # %if
+; CHECK-NEXT:    # in Loop: Header=BB0_2 Depth=1
+; CHECK-NEXT:    fmul.d fa3, fa3, fa5
+; CHECK-NEXT:    fsd fa3, 0(a0)
+; CHECK-NEXT:    j .LBB0_1
+; CHECK-NEXT:  .LBB0_4: # %exit
+; CHECK-NEXT:    ret
+entry:
+  br label %loop
+loop:
+  %iv = phi i64 [0, %entry], [%iv.next, %latch]
+  %gep = getelementptr double, ptr %p, i64 %iv
+  %x = load double, ptr %gep
+  %y0 = fmul double %x, %x
+  %y1 = fmul double %y0, %y0
+  %y2 = fmul double %y1, %y1
+  %y3 = fmul double %y2, %y2
+  %y4 = fmul double %y3, %y3
+  %y5 = fmul double %y4, %y4
+  %y6 = fmul double %y5, %y5
+  %y7 = fmul double %y6, %y6
+  %y8 = fmul double %y7, %y7
+  %y9 = fmul double %y8, %y8
+  %y10 = fmul double %y9, %y9
+  %y11 = fmul double %y10, %y10
+  %y12 = fmul double %y11, %y11
+  %y13 = fmul double %y12, %y12
+  %y14 = fmul double %y13, %y13
+  %y15 = fmul double %y14, %y14
+  %y16 = fmul double %y15, %y15
+  %y17 = fmul double %y16, %y16
+  %y18 = fmul double %y17, %y17
+  %y19 = fmul double %y18, %y18
+  %y20 = fmul double %y19, %y19
+  %y21 = fmul double %y20, %y20
+  %y22 = fmul double %y21, %y21
+  %y23 = fmul double %y22, %y22
+  %y24 = fmul double %y23, %y23
+  %y25 = fmul double %y24, %y24
+  %y26 = fmul double %y25, %y25
+  %y27 = fmul double %y26, %y26
+  %y28 = fmul double %y27, %y27
+  %y29 = fmul double %y28, %y28
+  %y30 = fmul double %y29, %y29
+  %y31 = fmul double %y30, %y30
+  %c = fcmp une double %y31, 0.0
+  br i1 %c, label %if, label %latch
+if:
+  ; The materialization of the constant 3.14159274101257324218750 should be hoisted 
+  ; out of the loop. MachineLICM should not be blocked by false register pressure 
+  ; from the multiple uses of the %yN variables.
+  %z = fmul double %y31, 3.14159274101257324218750
+  store double %z, ptr %gep
+  br label %latch
+latch:
+  %iv.next = add i64 %iv, 1
+  %ec = icmp eq i64 %iv.next, 1024
+  br i1 %ec, label %exit, label %loop
+exit:
+  ret void
+}

>From 88f4ad536fb5f60f1f2e72b744f3b86759fee358 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Tue, 21 Apr 2026 22:03:37 -0700
Subject: [PATCH 29/32] Address PR comments on SparseLiveVariables

- Do not ignore meta instructions
- Fuse loop over operands
- Use DenseMap::at instead of find
---
 .../llvm/CodeGen/SparseLiveVariables.h        | 38 ++++++++-----------
 llvm/lib/CodeGen/SparseLiveVariables.cpp      |  2 +-
 2 files changed, 17 insertions(+), 23 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/SparseLiveVariables.h b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
index 2e15278022f53..56a9ea875adf5 100644
--- a/llvm/include/llvm/CodeGen/SparseLiveVariables.h
+++ b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
@@ -90,26 +90,24 @@ class SparseLiveVariables : public MachineFunctionPass {
         : LiveRegs(LiveOut), MRI(MRI) {}
 
     void stepBackward(const MachineInstr &MI) {
-      if (MI.isDebugInstr() || MI.isMetaInstruction())
+      if (MI.isDebugInstr())
         return;
 
+      SmallVector<Register, 4> Uses;
       for (const MachineOperand &MO : MI.operands()) {
-        if (MO.isReg() && MO.isDef()) {
-          Register Reg = MO.getReg();
-          if (Reg.isValid() && isTrackableRegister(Reg))
-            LiveRegs.reset(Reg.id());
-        }
-      }
-
-      if (!MI.isPHI()) {
-        for (const MachineOperand &MO : MI.operands()) {
-          if (MO.isReg() && MO.isUse()) {
-            Register Reg = MO.getReg();
-            if (Reg.isValid() && isTrackableRegister(Reg))
-              LiveRegs.set(Reg.id());
-          }
-        }
+        if (!MO.isReg())
+          continue;
+        Register Reg = MO.getReg();
+        if (!Reg.isValid() || !isTrackableRegister(Reg))
+          continue;
+
+        if (MO.isDef())
+          LiveRegs.reset(Reg.id());
+        if (!MI.isPHI() && MO.isUse())
+          Uses.push_back(Reg);
       }
+      for (Register Reg : Uses)
+        LiveRegs.set(Reg.id());
     }
 
     bool isLive(Register Reg) const {
@@ -128,16 +126,12 @@ class SparseLiveVariables : public MachineFunctionPass {
 
   /// Returns the computed Live-In set for the given MachineBasicBlock.
   const SparseBitVector<> &getLiveInSet(const MachineBasicBlock *MBB) const {
-    auto It = BlockLiveness.find(MBB);
-    assert(It != BlockLiveness.end() && "Block not analyzed");
-    return It->second.LiveIn;
+    return BlockLiveness.at(MBB).LiveIn;
   }
 
   /// Returns the computed Live-Out set for the given MachineBasicBlock.
   const SparseBitVector<> &getLiveOutSet(const MachineBasicBlock *MBB) const {
-    auto It = BlockLiveness.find(MBB);
-    assert(It != BlockLiveness.end() && "Block not analyzed");
-    return It->second.LiveOut;
+    return BlockLiveness.at(MBB).LiveOut;
   }
 
   /// Returns true if Reg is live immediately AFTER the execution of MI.
diff --git a/llvm/lib/CodeGen/SparseLiveVariables.cpp b/llvm/lib/CodeGen/SparseLiveVariables.cpp
index 214da2e122cf2..2d59a66a8f2b1 100644
--- a/llvm/lib/CodeGen/SparseLiveVariables.cpp
+++ b/llvm/lib/CodeGen/SparseLiveVariables.cpp
@@ -183,7 +183,7 @@ void SparseLiveVariables::updateKillFlags(MachineFunction &MF) const {
 
     LivenessTracker Tracker(It->second.LiveOut, MRI);
     for (MachineInstr &MI : llvm::reverse(MBB)) {
-      if (MI.isDebugInstr() || MI.isMetaInstruction())
+      if (MI.isDebugInstr())
         continue;
 
       // Check uses and update their kill flags based on whether they are live

>From 9590d53a21bf9cae537f2bbdfe4facb3906f86d9 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Tue, 21 Apr 2026 22:08:26 -0700
Subject: [PATCH 30/32] Remove deprecated updateKillFlags method

As per PR review feedback, kill flags are deprecated and we shouldn't
be computing or depending on them. This removes the unused
updateKillFlags method and its associated test.
---
 .../llvm/CodeGen/SparseLiveVariables.h        |  8 ++---
 llvm/lib/CodeGen/SparseLiveVariables.cpp      | 33 -------------------
 .../CodeGen/SparseLiveVariablesTest.cpp       |  9 -----
 3 files changed, 2 insertions(+), 48 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/SparseLiveVariables.h b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
index 56a9ea875adf5..5ae0d6dbce797 100644
--- a/llvm/include/llvm/CodeGen/SparseLiveVariables.h
+++ b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
@@ -45,8 +45,8 @@ namespace llvm {
 /// This pass computes block-level live-in and live-out sets using a
 /// SparseBitVector representation. It is designed to be a lightweight,
 /// memory-efficient alternative to the legacy LiveVariables pass. It operates
-/// as a read-only analysis but provides mutation APIs (`updateLiveIns`,
-/// `updateKillFlags`) to explicitly update the IR state if desired.
+/// as a read-only analysis but provides mutation APIs (`updateLiveIns`)
+/// to explicitly update the IR state if desired.
 class SparseLiveVariables : public MachineFunctionPass {
 public:
   static char ID;
@@ -181,10 +181,6 @@ class SparseLiveVariables : public MachineFunctionPass {
   /// Update the live-ins of all basic blocks in MF based on computed liveness.
   void updateLiveIns(MachineFunction &MF) const;
 
-  /// Update the kill flags of all instructions in MF based on computed
-  /// liveness.
-  void updateKillFlags(MachineFunction &MF) const;
-
   bool runOnMachineFunction(MachineFunction &MF) override;
 
   StringRef getPassName() const override {
diff --git a/llvm/lib/CodeGen/SparseLiveVariables.cpp b/llvm/lib/CodeGen/SparseLiveVariables.cpp
index 2d59a66a8f2b1..6c3695279be51 100644
--- a/llvm/lib/CodeGen/SparseLiveVariables.cpp
+++ b/llvm/lib/CodeGen/SparseLiveVariables.cpp
@@ -175,40 +175,7 @@ void SparseLiveVariables::updateLiveIns(MachineFunction &MF) const {
   }
 }
 
-void SparseLiveVariables::updateKillFlags(MachineFunction &MF) const {
-  for (MachineBasicBlock &MBB : MF) {
-    auto It = BlockLiveness.find(&MBB);
-    if (It == BlockLiveness.end())
-      continue;
-
-    LivenessTracker Tracker(It->second.LiveOut, MRI);
-    for (MachineInstr &MI : llvm::reverse(MBB)) {
-      if (MI.isDebugInstr())
-        continue;
 
-      // Check uses and update their kill flags based on whether they are live
-      // BEFORE stepBackward. (Tracker currently represents the liveness state
-      // AFTER this instruction).
-      for (MachineOperand &MO : MI.operands()) {
-        if (!MO.isReg() || !MO.isUse())
-          continue;
-        Register Reg = MO.getReg();
-        if (!Tracker.isTrackableRegister(Reg))
-          continue;
-
-        if (!Tracker.isLive(Reg)) {
-          // If the register is not live after this instruction, it is a kill.
-          MO.setIsKill(true);
-        } else {
-          // Otherwise, clear the kill flag if it was set incorrectly.
-          MO.setIsKill(false);
-        }
-      }
-
-      Tracker.stepBackward(MI);
-    }
-  }
-}
 
 void SparseLiveVariables::recomputeRegisterLiveness(Register Reg,
                                                     MachineInstr *IgnoreMI) {
diff --git a/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp b/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
index 4b938ab7c0531..5748a5051de63 100644
--- a/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
+++ b/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
@@ -96,15 +96,6 @@ TEST(SparseLiveVariablesTest, APITests) {
   EXPECT_FALSE(LiveOut.test(Reg1.id()));
   EXPECT_FALSE(LiveOut.test(Reg2.id()));
 
-  // Test the mutation APIs
-  LV.updateKillFlags(*MF);
-
-  // Reg0 should have a kill flag on MI1
-  EXPECT_TRUE(MI1->getOperand(1).isKill());
-
-  // Reg1 should have a kill flag on MI2
-  EXPECT_TRUE(MI2->getOperand(1).isKill());
-
   // Test updateLiveIns (won't add virtual registers, but shouldn't crash)
   LV.updateLiveIns(*MF);
   EXPECT_TRUE(MBB->livein_empty());

>From ac1a455a8ef0c9fb19df3d6ae025ac6484c04734 Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Tue, 21 Apr 2026 22:45:23 -0700
Subject: [PATCH 31/32] Address remaining PR comments for SparseLiveVariables

- Replaced DenseMap with std::vector for BlockLiveness, indexing by MBB->getNumber()
  to resolve undefined behavior and improve performance.
- Removed redundant reachability checks.
- Documented vector gap behavior and overall pass design.
---
 .../llvm/CodeGen/SparseLiveVariables.h        |  23 ++-
 llvm/lib/CodeGen/SparseLiveVariables.cpp      | 152 +++++++++---------
 2 files changed, 95 insertions(+), 80 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/SparseLiveVariables.h b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
index 5ae0d6dbce797..267a55499f06c 100644
--- a/llvm/include/llvm/CodeGen/SparseLiveVariables.h
+++ b/llvm/include/llvm/CodeGen/SparseLiveVariables.h
@@ -58,7 +58,13 @@ class SparseLiveVariables : public MachineFunctionPass {
     SparseBitVector<> LiveOut;
   };
 
-  DenseMap<const MachineBasicBlock *, BlockInfo> BlockLiveness;
+  /// Liveness information per block, indexed by MBB->getNumber().
+  /// We size this vector to MF.getNumBlockIDs() to guarantee bounds safety.
+  /// Note: Block numbers may have gaps if blocks were deleted. We intentionally
+  /// leave these gap indices empty (unused) rather than calling
+  /// MF.RenumberBlocks(), as doing so would mutate the function and invalidate
+  /// other analysis passes.
+  std::vector<BlockInfo> BlockLiveness;
 
   /// LivenessTracker - A utility class for backward liveness traversal.
   ///
@@ -121,17 +127,20 @@ class SparseLiveVariables : public MachineFunctionPass {
 
   /// Returns true if the given MachineBasicBlock has been analyzed.
   bool hasAnalyzed(const MachineBasicBlock *MBB) const {
-    return BlockLiveness.count(MBB);
+    return MBB->getNumber() >= 0 &&
+           (size_t)MBB->getNumber() < BlockLiveness.size();
   }
 
   /// Returns the computed Live-In set for the given MachineBasicBlock.
   const SparseBitVector<> &getLiveInSet(const MachineBasicBlock *MBB) const {
-    return BlockLiveness.at(MBB).LiveIn;
+    assert(hasAnalyzed(MBB) && "Block not analyzed");
+    return BlockLiveness[MBB->getNumber()].LiveIn;
   }
 
   /// Returns the computed Live-Out set for the given MachineBasicBlock.
   const SparseBitVector<> &getLiveOutSet(const MachineBasicBlock *MBB) const {
-    return BlockLiveness.at(MBB).LiveOut;
+    assert(hasAnalyzed(MBB) && "Block not analyzed");
+    return BlockLiveness[MBB->getNumber()].LiveOut;
   }
 
   /// Returns true if Reg is live immediately AFTER the execution of MI.
@@ -159,7 +168,8 @@ class SparseLiveVariables : public MachineFunctionPass {
   /// \param IgnoreMI An optional instruction to ignore during recomputation
   ///                 (useful for removing liveness before an instruction is
   ///                 physically deleted).
-  void recomputeRegisterLiveness(Register Reg, MachineInstr *IgnoreMI = nullptr);
+  void recomputeRegisterLiveness(Register Reg,
+                                 MachineInstr *IgnoreMI = nullptr);
 
   /// \brief Update liveness after a pass adds a new instruction.
   void addInstruction(MachineInstr &MI, MachineBasicBlock *MBB);
@@ -170,7 +180,8 @@ class SparseLiveVariables : public MachineFunctionPass {
   void removeInstruction(MachineInstr &MI);
 
   /// \brief Update liveness after a pass moves an instruction.
-  void handleMove(MachineInstr &MI, MachineBasicBlock *OldBB, MachineBasicBlock *NewBB);
+  void handleMove(MachineInstr &MI, MachineBasicBlock *OldBB,
+                  MachineBasicBlock *NewBB);
 
   /// \brief Update the live-in list of each MachineBasicBlock.
   ///
diff --git a/llvm/lib/CodeGen/SparseLiveVariables.cpp b/llvm/lib/CodeGen/SparseLiveVariables.cpp
index 6c3695279be51..5d7e11b4ad29b 100644
--- a/llvm/lib/CodeGen/SparseLiveVariables.cpp
+++ b/llvm/lib/CodeGen/SparseLiveVariables.cpp
@@ -5,6 +5,22 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+//
+// This file implements the SparseLiveVariables analysis pass.
+//
+// This pass computes block-level live-in and live-out sets using a memory
+// efficient SparseBitVector representation. Unlike the legacy LiveVariables
+// pass, this analysis is completely stateless at the instruction level. It
+// relies on a fixed-point dataflow iteration over the control flow graph to
+// establish block boundary conditions. Instruction-level queries are evaluated
+// dynamically via the LivenessTracker by traversing backwards from the end
+// of a block.
+//
+// This modern, target-independent pass is designed to handle very large
+// virtual register sets without the massive memory overhead traditionally
+// associated with dense bit-vectors and heavily cached liveness states.
+//
+//===----------------------------------------------------------------------===//
 
 #include "llvm/CodeGen/SparseLiveVariables.h"
 #include "llvm/ADT/DepthFirstIterator.h"
@@ -34,7 +50,7 @@ bool SparseLiveVariables::runOnMachineFunction(MachineFunction &MF) {
   MRI = &MF.getRegInfo();
   TRI = MF.getSubtarget().getRegisterInfo();
 
-  BlockLiveness.clear();
+  BlockLiveness.assign(MF.getNumBlockIDs(), BlockInfo());
 
   SmallPtrSet<MachineBasicBlock *, 16> Reachable;
   for (MachineBasicBlock *MBB : llvm::depth_first(&MF))
@@ -47,23 +63,27 @@ bool SparseLiveVariables::runOnMachineFunction(MachineFunction &MF) {
       if (!Reachable.count(MBB))
         continue;
 
-      SparseBitVector<> OldLiveIn = BlockLiveness[MBB].LiveIn;
-      SparseBitVector<> OldLiveOut = BlockLiveness[MBB].LiveOut;
+      SparseBitVector<> OldLiveIn = BlockLiveness[MBB->getNumber()].LiveIn;
+      SparseBitVector<> OldLiveOut = BlockLiveness[MBB->getNumber()].LiveOut;
 
-      for (const MachineBasicBlock *Succ : MBB->successors())
-        if (Reachable.count(Succ))
-          BlockLiveness[MBB].LiveOut |= BlockLiveness[Succ].LiveIn;
+      SparseBitVector<> LiveOut;
+      for (const MachineBasicBlock *Succ : MBB->successors()) {
+        if (!Reachable.count(Succ))
+          continue;
+        LiveOut |= BlockLiveness[Succ->getNumber()].LiveIn;
+      }
+      BlockLiveness[MBB->getNumber()].LiveOut = LiveOut;
 
-      SparseBitVector<> LiveIn = BlockLiveness[MBB].LiveOut;
+      SparseBitVector<> LiveIn = BlockLiveness[MBB->getNumber()].LiveOut;
       LivenessTracker Tracker(LiveIn, MRI);
 
       for (MachineInstr &MI : llvm::reverse(*MBB))
         Tracker.stepBackward(MI);
 
-      BlockLiveness[MBB].LiveIn = Tracker.getLiveSet();
+      BlockLiveness[MBB->getNumber()].LiveIn = Tracker.getLiveSet();
 
-      if (BlockLiveness[MBB].LiveIn != OldLiveIn ||
-          BlockLiveness[MBB].LiveOut != OldLiveOut)
+      if (BlockLiveness[MBB->getNumber()].LiveIn != OldLiveIn ||
+          BlockLiveness[MBB->getNumber()].LiveOut != OldLiveOut)
         Changed = true;
     }
   }
@@ -93,11 +113,10 @@ bool SparseLiveVariables::runOnMachineFunction(MachineFunction &MF) {
 bool SparseLiveVariables::isLiveAfter(Register Reg,
                                       const MachineInstr &MI) const {
   const MachineBasicBlock *MBB = MI.getParent();
-  auto It = BlockLiveness.find(MBB);
-  if (It == BlockLiveness.end())
+  if (!hasAnalyzed(MBB))
     return false;
 
-  LivenessTracker Tracker(It->second.LiveOut, MRI);
+  LivenessTracker Tracker(BlockLiveness[MBB->getNumber()].LiveOut, MRI);
   for (const MachineInstr &I : llvm::reverse(*MBB)) {
     if (&I == &MI)
       return Tracker.isLive(Reg);
@@ -108,11 +127,10 @@ bool SparseLiveVariables::isLiveAfter(Register Reg,
 
 bool SparseLiveVariables::isLiveAt(Register Reg, const MachineInstr &MI) const {
   const MachineBasicBlock *MBB = MI.getParent();
-  auto It = BlockLiveness.find(MBB);
-  if (It == BlockLiveness.end())
+  if (!hasAnalyzed(MBB))
     return false;
 
-  LivenessTracker Tracker(It->second.LiveOut, MRI);
+  LivenessTracker Tracker(BlockLiveness[MBB->getNumber()].LiveOut, MRI);
   for (const MachineInstr &I : llvm::reverse(*MBB)) {
     Tracker.stepBackward(I);
     if (&I == &MI)
@@ -123,11 +141,10 @@ bool SparseLiveVariables::isLiveAt(Register Reg, const MachineInstr &MI) const {
 
 bool SparseLiveVariables::isKillAt(Register Reg, const MachineInstr &MI) const {
   const MachineBasicBlock *MBB = MI.getParent();
-  auto It = BlockLiveness.find(MBB);
-  if (It == BlockLiveness.end())
+  if (!hasAnalyzed(MBB))
     return false;
 
-  LivenessTracker Tracker(It->second.LiveOut, MRI);
+  LivenessTracker Tracker(BlockLiveness[MBB->getNumber()].LiveOut, MRI);
   for (const MachineInstr &I : llvm::reverse(*MBB)) {
     bool LiveAfter = Tracker.isLive(Reg);
     Tracker.stepBackward(I);
@@ -142,11 +159,10 @@ bool SparseLiveVariables::isKillAt(Register Reg, const MachineInstr &MI) const {
 
 void SparseLiveVariables::verifyLiveness(const MachineFunction &MF) const {
   for (const MachineBasicBlock &MBB : MF) {
-    auto It = BlockLiveness.find(&MBB);
-    if (It == BlockLiveness.end())
+    if (!hasAnalyzed(&MBB))
       continue;
 
-    const SparseBitVector<> &LiveIn = It->second.LiveIn;
+    const SparseBitVector<> &LiveIn = BlockLiveness[MBB.getNumber()].LiveIn;
     for (const auto &LI : MBB.liveins()) {
       if (!LiveIn.test(LI.PhysReg.id())) {
         LLVM_DEBUG(dbgs() << "Warning: Live-in register "
@@ -159,12 +175,11 @@ void SparseLiveVariables::verifyLiveness(const MachineFunction &MF) const {
 }
 void SparseLiveVariables::updateLiveIns(MachineFunction &MF) const {
   for (MachineBasicBlock &MBB : MF) {
-    auto It = BlockLiveness.find(&MBB);
-    if (It == BlockLiveness.end())
+    if (!hasAnalyzed(&MBB))
       continue;
 
     MBB.clearLiveIns();
-    const SparseBitVector<> &LiveIn = It->second.LiveIn;
+    const SparseBitVector<> &LiveIn = BlockLiveness[MBB.getNumber()].LiveIn;
     for (unsigned RegID : LiveIn) {
       Register Reg(RegID);
       // MBB.addLiveIn only takes physical registers.
@@ -175,17 +190,15 @@ void SparseLiveVariables::updateLiveIns(MachineFunction &MF) const {
   }
 }
 
-
-
 void SparseLiveVariables::recomputeRegisterLiveness(Register Reg,
                                                     MachineInstr *IgnoreMI) {
   if (!Reg.isVirtual())
     return;
 
   // 1. Clear Reg from all blocks
-  for (auto &KV : BlockLiveness) {
-    KV.second.LiveIn.reset(Reg.id());
-    KV.second.LiveOut.reset(Reg.id());
+  for (unsigned i = 0, e = BlockLiveness.size(); i != e; ++i) {
+    BlockLiveness[i].LiveIn.reset(Reg.id());
+    BlockLiveness[i].LiveOut.reset(Reg.id());
   }
 
   // 2. Propagate from all uses
@@ -204,10 +217,9 @@ void SparseLiveVariables::recomputeRegisterLiveness(Register Reg,
         if (UseMI.getOperand(i).isReg() &&
             UseMI.getOperand(i).getReg() == Reg) {
           MachineBasicBlock *Pred = UseMI.getOperand(i + 1).getMBB();
-          auto PredIt = BlockLiveness.find(Pred);
-          if (PredIt != BlockLiveness.end()) {
-            if (!PredIt->second.LiveOut.test(Reg.id())) {
-              PredIt->second.LiveOut.set(Reg.id());
+          if (hasAnalyzed(Pred)) {
+            if (!BlockLiveness[Pred->getNumber()].LiveOut.test(Reg.id())) {
+              BlockLiveness[Pred->getNumber()].LiveOut.set(Reg.id());
               WorkList.push_back(Pred);
             }
           }
@@ -228,10 +240,9 @@ void SparseLiveVariables::recomputeRegisterLiveness(Register Reg,
     }
 
     if (!FoundDef) {
-      auto It = BlockLiveness.find(MBB);
-      if (It != BlockLiveness.end()) {
-        if (!It->second.LiveIn.test(Reg.id())) {
-          It->second.LiveIn.set(Reg.id());
+      if (hasAnalyzed(MBB)) {
+        if (!BlockLiveness[MBB->getNumber()].LiveIn.test(Reg.id())) {
+          BlockLiveness[MBB->getNumber()].LiveIn.set(Reg.id());
           WorkList.push_back(MBB);
         }
       }
@@ -243,12 +254,11 @@ void SparseLiveVariables::recomputeRegisterLiveness(Register Reg,
     MachineBasicBlock *Curr = WorkList.pop_back_val();
 
     for (MachineBasicBlock *Pred : Curr->predecessors()) {
-      auto PredIt = BlockLiveness.find(Pred);
-      if (PredIt == BlockLiveness.end())
+      if (!hasAnalyzed(Pred))
         continue;
 
-      if (!PredIt->second.LiveOut.test(Reg.id())) {
-        PredIt->second.LiveOut.set(Reg.id());
+      if (!BlockLiveness[Pred->getNumber()].LiveOut.test(Reg.id())) {
+        BlockLiveness[Pred->getNumber()].LiveOut.set(Reg.id());
 
         bool FoundDef = false;
         for (const MachineInstr &MI : llvm::reverse(*Pred)) {
@@ -261,8 +271,8 @@ void SparseLiveVariables::recomputeRegisterLiveness(Register Reg,
         }
 
         if (!FoundDef) {
-          if (!PredIt->second.LiveIn.test(Reg.id())) {
-            PredIt->second.LiveIn.set(Reg.id());
+          if (!BlockLiveness[Pred->getNumber()].LiveIn.test(Reg.id())) {
+            BlockLiveness[Pred->getNumber()].LiveIn.set(Reg.id());
             WorkList.push_back(Pred);
           }
         }
@@ -286,17 +296,16 @@ bool SparseLiveVariables::evaluateLiveIn(Register Reg, MachineBasicBlock *MBB,
     if (BlockMI.definesRegister(Reg, TRI))
       return false;
   }
-  auto It = BlockLiveness.find(MBB);
-  if (It != BlockLiveness.end())
-    return It->second.LiveOut.test(Reg.id());
+  if (hasAnalyzed(MBB))
+    return BlockLiveness[MBB->getNumber()].LiveOut.test(Reg.id());
   return false;
 }
 
 bool SparseLiveVariables::isLiveOut(Register Reg, MachineBasicBlock *MBB,
                                     MachineInstr *IgnoreMI) const {
   for (MachineBasicBlock *Succ : MBB->successors()) {
-    auto SuccIt = BlockLiveness.find(Succ);
-    if (SuccIt != BlockLiveness.end() && SuccIt->second.LiveIn.test(Reg.id()))
+    if (hasAnalyzed(Succ) &&
+        BlockLiveness[Succ->getNumber()].LiveIn.test(Reg.id()))
       return true;
 
     for (const MachineInstr &OtherPHI : *Succ) {
@@ -318,19 +327,18 @@ bool SparseLiveVariables::isLiveOut(Register Reg, MachineBasicBlock *MBB,
 
 void SparseLiveVariables::reevaluateLiveIn(Register Reg, MachineBasicBlock *MBB,
                                            MachineInstr *IgnoreMI) {
-  auto It = BlockLiveness.find(MBB);
-  if (It == BlockLiveness.end())
+  if (!hasAnalyzed(MBB))
     return;
 
-  bool OldLiveIn = It->second.LiveIn.test(Reg.id());
+  bool OldLiveIn = BlockLiveness[MBB->getNumber()].LiveIn.test(Reg.id());
   bool NewLiveIn = evaluateLiveIn(Reg, MBB, IgnoreMI);
 
   if (OldLiveIn != NewLiveIn) {
     if (NewLiveIn) {
-      It->second.LiveIn.set(Reg.id());
+      BlockLiveness[MBB->getNumber()].LiveIn.set(Reg.id());
       propagateGrowth(Reg, MBB, IgnoreMI);
     } else {
-      It->second.LiveIn.reset(Reg.id());
+      BlockLiveness[MBB->getNumber()].LiveIn.reset(Reg.id());
       propagateShrinkage(Reg, MBB, IgnoreMI);
     }
   }
@@ -345,16 +353,15 @@ void SparseLiveVariables::propagateGrowth(Register Reg,
   while (!WorkList.empty()) {
     MachineBasicBlock *Curr = WorkList.pop_back_val();
     for (MachineBasicBlock *Pred : Curr->predecessors()) {
-      auto PredIt = BlockLiveness.find(Pred);
-      if (PredIt == BlockLiveness.end())
+      if (!hasAnalyzed(Pred))
         continue;
 
-      if (!PredIt->second.LiveOut.test(Reg.id())) {
-        PredIt->second.LiveOut.set(Reg.id());
+      if (!BlockLiveness[Pred->getNumber()].LiveOut.test(Reg.id())) {
+        BlockLiveness[Pred->getNumber()].LiveOut.set(Reg.id());
 
-        if (!PredIt->second.LiveIn.test(Reg.id())) {
+        if (!BlockLiveness[Pred->getNumber()].LiveIn.test(Reg.id())) {
           if (evaluateLiveIn(Reg, Pred, IgnoreMI)) {
-            PredIt->second.LiveIn.set(Reg.id());
+            BlockLiveness[Pred->getNumber()].LiveIn.set(Reg.id());
             WorkList.push_back(Pred);
           }
         }
@@ -372,19 +379,18 @@ void SparseLiveVariables::propagateShrinkage(Register Reg,
   while (!WorkList.empty()) {
     MachineBasicBlock *Curr = WorkList.pop_back_val();
     for (MachineBasicBlock *Pred : Curr->predecessors()) {
-      auto PredIt = BlockLiveness.find(Pred);
-      if (PredIt == BlockLiveness.end())
+      if (!hasAnalyzed(Pred))
         continue;
 
-      if (!PredIt->second.LiveOut.test(Reg.id()))
+      if (!BlockLiveness[Pred->getNumber()].LiveOut.test(Reg.id()))
         continue;
 
       if (!isLiveOut(Reg, Pred, IgnoreMI)) {
-        PredIt->second.LiveOut.reset(Reg.id());
+        BlockLiveness[Pred->getNumber()].LiveOut.reset(Reg.id());
 
-        if (PredIt->second.LiveIn.test(Reg.id())) {
+        if (BlockLiveness[Pred->getNumber()].LiveIn.test(Reg.id())) {
           if (!evaluateLiveIn(Reg, Pred, IgnoreMI)) {
-            PredIt->second.LiveIn.reset(Reg.id());
+            BlockLiveness[Pred->getNumber()].LiveIn.reset(Reg.id());
             WorkList.push_back(Pred);
           }
         }
@@ -414,10 +420,9 @@ void SparseLiveVariables::addInstruction(MachineInstr &MI,
       }
 
       if (Pred) {
-        auto PredIt = BlockLiveness.find(Pred);
-        if (PredIt != BlockLiveness.end() &&
-            !PredIt->second.LiveOut.test(Reg.id())) {
-          PredIt->second.LiveOut.set(Reg.id());
+        if (hasAnalyzed(Pred) &&
+            !BlockLiveness[Pred->getNumber()].LiveOut.test(Reg.id())) {
+          BlockLiveness[Pred->getNumber()].LiveOut.set(Reg.id());
           reevaluateLiveIn(Reg, Pred);
         }
       }
@@ -447,11 +452,10 @@ void SparseLiveVariables::removeInstruction(MachineInstr &MI) {
       }
 
       if (Pred) {
-        auto PredIt = BlockLiveness.find(Pred);
-        if (PredIt != BlockLiveness.end() &&
-            PredIt->second.LiveOut.test(Reg.id())) {
+        if (hasAnalyzed(Pred) &&
+            BlockLiveness[Pred->getNumber()].LiveOut.test(Reg.id())) {
           if (!isLiveOut(Reg, Pred, &MI)) {
-            PredIt->second.LiveOut.reset(Reg.id());
+            BlockLiveness[Pred->getNumber()].LiveOut.reset(Reg.id());
             reevaluateLiveIn(Reg, Pred, &MI);
           }
         }

>From d096b0ea720bc13b917cd2b9ec4332614cfb54be Mon Sep 17 00:00:00 2001
From: AdityaK <hiraditya at msn.com>
Date: Wed, 22 Apr 2026 06:44:14 -0700
Subject: [PATCH 32/32] [SparseLiveVariables] Add full unit test coverage and
 fix LiveOut PHI bug

---
 llvm/lib/CodeGen/SparseLiveVariables.cpp      |  19 ++
 .../CodeGen/SparseLiveVariablesTest.cpp       | 266 ++++++++++++++++++
 2 files changed, 285 insertions(+)

diff --git a/llvm/lib/CodeGen/SparseLiveVariables.cpp b/llvm/lib/CodeGen/SparseLiveVariables.cpp
index 5d7e11b4ad29b..285e2ba75edfe 100644
--- a/llvm/lib/CodeGen/SparseLiveVariables.cpp
+++ b/llvm/lib/CodeGen/SparseLiveVariables.cpp
@@ -71,6 +71,25 @@ bool SparseLiveVariables::runOnMachineFunction(MachineFunction &MF) {
         if (!Reachable.count(Succ))
           continue;
         LiveOut |= BlockLiveness[Succ->getNumber()].LiveIn;
+
+        // PHI nodes have special liveness semantics: their uses are evaluated
+        // conditionally on the incoming edge, meaning they are NOT Live-In to
+        // the block containing the PHI node. Therefore, we cannot rely solely
+        // on unioning the successor's LiveIn set. We must actively scan the
+        // successor's PHI nodes and add any registers explicitly tied to the
+        // incoming edge from this MBB directly into our LiveOut set.
+        for (const MachineInstr &MI : *Succ) {
+          if (!MI.isPHI())
+            break;
+          for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
+            if (MI.getOperand(i).isReg() &&
+                MI.getOperand(i + 1).getMBB() == MBB) {
+              Register Reg = MI.getOperand(i).getReg();
+              if (Reg.isValid() && Reg.isVirtual())
+                LiveOut.set(Reg.id());
+            }
+          }
+        }
       }
       BlockLiveness[MBB->getNumber()].LiveOut = LiveOut;
 
diff --git a/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp b/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
index 5748a5051de63..325216325c239 100644
--- a/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
+++ b/llvm/unittests/CodeGen/SparseLiveVariablesTest.cpp
@@ -11,9 +11,15 @@
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/MachineOperand.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetFrameLowering.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/IR/Module.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCSymbol.h"
@@ -156,4 +162,264 @@ TEST(SparseLiveVariablesTest, IncrementalLivenessUpdates) {
   EXPECT_FALSE(LV.getLiveInSet(MBB2).test(Reg0.id()));
 }
 
+TEST(SparseLiveVariablesTest, RecomputeRegisterLiveness) {
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
+  auto MBB1 = MF->CreateMachineBasicBlock();
+  auto MBB2 = MF->CreateMachineBasicBlock();
+  MF->push_back(MBB1);
+  MF->push_back(MBB2);
+  MBB1->addSuccessor(MBB2);
+
+  MCInstrDesc MCID = {100, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+
+  MCRegisterClass MRC{
+      0, 0, 0, 0, 0, 0, 0, 0, /*Allocatable=*/true, /*BaseClass=*/true};
+  TargetRegisterClass RC{&MRC, 0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0};
+  MachineRegisterInfo &MRI = MF->getRegInfo();
+
+  Register Reg0 = MRI.createVirtualRegister(&RC);
+  Register Reg1 = MRI.createVirtualRegister(&RC);
+
+  // MI1 in MBB1: %0 = OP
+  MachineInstr *MI1 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI1->addOperand(*MF, MachineOperand::CreateReg(Reg0, /*isDef*/ true));
+  MBB1->insert(MBB1->end(), MI1);
+
+  // MI2 in MBB2: %1 = OP %0
+  MachineInstr *MI2 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg1, /*isDef*/ true));
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg0, /*isDef*/ false));
+  MBB2->insert(MBB2->end(), MI2);
+
+  SparseLiveVariables LV;
+  LV.runOnMachineFunction(*MF);
+
+  EXPECT_TRUE(LV.getLiveOutSet(MBB1).test(Reg0.id()));
+  EXPECT_TRUE(LV.getLiveInSet(MBB2).test(Reg0.id()));
+
+  // Manually remove MI2 from MBB2 without informing LV using removeInstruction
+  MBB2->erase(MI2);
+
+  // LV still thinks Reg0 is live
+  EXPECT_TRUE(LV.getLiveOutSet(MBB1).test(Reg0.id()));
+  EXPECT_TRUE(LV.getLiveInSet(MBB2).test(Reg0.id()));
+
+  // Recompute liveness for Reg0
+  LV.recomputeRegisterLiveness(Reg0);
+
+  // Now it should be updated
+  EXPECT_FALSE(LV.getLiveOutSet(MBB1).test(Reg0.id()));
+  EXPECT_FALSE(LV.getLiveInSet(MBB2).test(Reg0.id()));
+}
+
+TEST(SparseLiveVariablesTest, HandleMoveUpdatesLiveness) {
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
+  auto MBB1 = MF->CreateMachineBasicBlock();
+  auto MBB2 = MF->CreateMachineBasicBlock();
+  auto MBB3 = MF->CreateMachineBasicBlock();
+  MF->push_back(MBB1);
+  MF->push_back(MBB2);
+  MF->push_back(MBB3);
+  MBB1->addSuccessor(MBB2);
+  MBB2->addSuccessor(MBB3);
+
+  MCInstrDesc MCID = {100, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+
+  MCRegisterClass MRC{
+      0, 0, 0, 0, 0, 0, 0, 0, /*Allocatable=*/true, /*BaseClass=*/true};
+  TargetRegisterClass RC{&MRC, 0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0};
+  MachineRegisterInfo &MRI = MF->getRegInfo();
+
+  Register Reg0 = MRI.createVirtualRegister(&RC);
+  Register Reg1 = MRI.createVirtualRegister(&RC);
+
+  // MI1 in MBB1: %0 = OP
+  MachineInstr *MI1 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI1->addOperand(*MF, MachineOperand::CreateReg(Reg0, /*isDef*/ true));
+  MBB1->insert(MBB1->end(), MI1);
+
+  // MI2 in MBB2: %1 = OP %0
+  MachineInstr *MI2 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg1, /*isDef*/ true));
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg0, /*isDef*/ false));
+  MBB2->insert(MBB2->end(), MI2);
+
+  SparseLiveVariables LV;
+  LV.runOnMachineFunction(*MF);
+
+  EXPECT_TRUE(LV.getLiveOutSet(MBB1).test(Reg0.id()));
+  EXPECT_TRUE(LV.getLiveInSet(MBB2).test(Reg0.id()));
+  EXPECT_FALSE(LV.getLiveOutSet(MBB2).test(Reg0.id()));
+  EXPECT_FALSE(LV.getLiveInSet(MBB3).test(Reg0.id()));
+
+  // Move MI2 from MBB2 to MBB3
+  MBB3->splice(MBB3->end(), MBB2, MI2);
+  LV.handleMove(*MI2, MBB2, MBB3);
+
+  // Liveness should now flow through MBB2 to MBB3
+  EXPECT_TRUE(LV.getLiveOutSet(MBB1).test(Reg0.id()));
+  EXPECT_TRUE(LV.getLiveInSet(MBB2).test(Reg0.id()));
+  EXPECT_TRUE(LV.getLiveOutSet(MBB2).test(Reg0.id()));
+  EXPECT_TRUE(LV.getLiveInSet(MBB3).test(Reg0.id()));
+}
+
+TEST(SparseLiveVariablesTest, InstructionLevelLivenessTracking) {
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
+  auto MBB = MF->CreateMachineBasicBlock();
+  MF->push_back(MBB);
+
+  MCInstrDesc MCID = {100, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+
+  MCRegisterClass MRC{
+      0, 0, 0, 0, 0, 0, 0, 0, /*Allocatable=*/true, /*BaseClass=*/true};
+  TargetRegisterClass RC{&MRC, 0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0};
+  MachineRegisterInfo &MRI = MF->getRegInfo();
+
+  Register Reg0 = MRI.createVirtualRegister(&RC);
+  Register Reg1 = MRI.createVirtualRegister(&RC);
+  Register Reg2 = MRI.createVirtualRegister(&RC);
+
+  // MI1: %0 = OP
+  MachineInstr *MI1 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI1->addOperand(*MF, MachineOperand::CreateReg(Reg0, /*isDef*/ true));
+  MBB->insert(MBB->end(), MI1);
+
+  // MI2: %1 = OP %0
+  MachineInstr *MI2 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg1, /*isDef*/ true));
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg0, /*isDef*/ false));
+  MBB->insert(MBB->end(), MI2);
+
+  // MI3: %2 = OP %0
+  MachineInstr *MI3 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI3->addOperand(*MF, MachineOperand::CreateReg(Reg2, /*isDef*/ true));
+  MI3->addOperand(*MF, MachineOperand::CreateReg(Reg0, /*isDef*/ false));
+  MBB->insert(MBB->end(), MI3);
+
+  SparseLiveVariables LV;
+  LV.runOnMachineFunction(*MF);
+
+  // Reg0 is defined at MI1, used at MI2, and killed at MI3.
+  EXPECT_FALSE(LV.isKillAt(Reg0, *MI2));
+  EXPECT_TRUE(LV.isKillAt(Reg0, *MI3));
+
+  EXPECT_TRUE(LV.isLiveAfter(Reg0, *MI2));
+  EXPECT_FALSE(LV.isLiveAfter(Reg0, *MI3));
+}
+
+TEST(SparseLiveVariablesTest, PhiNodeLiveness) {
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
+  auto MBB0 = MF->CreateMachineBasicBlock();
+  auto MBB1 = MF->CreateMachineBasicBlock();
+  auto MBB2 = MF->CreateMachineBasicBlock();
+  auto MBB3 = MF->CreateMachineBasicBlock();
+  MF->push_back(MBB0);
+  MF->push_back(MBB1);
+  MF->push_back(MBB2);
+  MF->push_back(MBB3);
+  MBB0->addSuccessor(MBB1);
+  MBB0->addSuccessor(MBB2);
+  MBB1->addSuccessor(MBB3);
+  MBB2->addSuccessor(MBB3);
+
+  MCInstrDesc MCID = {100, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+
+  MCRegisterClass MRC{
+      0, 0, 0, 0, 0, 0, 0, 0, /*Allocatable=*/true, /*BaseClass=*/true};
+  TargetRegisterClass RC{&MRC, 0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0};
+  MachineRegisterInfo &MRI = MF->getRegInfo();
+
+  Register Reg1 = MRI.createVirtualRegister(&RC);
+  Register Reg2 = MRI.createVirtualRegister(&RC);
+  Register Reg3 = MRI.createVirtualRegister(&RC);
+
+  // MBB1: %1 = OP
+  MachineInstr *MI1 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI1->addOperand(*MF, MachineOperand::CreateReg(Reg1, /*isDef*/ true));
+  MBB1->insert(MBB1->end(), MI1);
+
+  // MBB2: %2 = OP
+  MachineInstr *MI2 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg2, /*isDef*/ true));
+  MBB2->insert(MBB2->end(), MI2);
+
+  // MBB3: %3 = PHI %1, MBB1, %2, MBB2
+  MCInstrDesc PHIMCID = {TargetOpcode::PHI, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  MachineInstr *MI3 = MF->CreateMachineInstr(PHIMCID, DebugLoc());
+  MI3->addOperand(*MF, MachineOperand::CreateReg(Reg3, /*isDef*/ true));
+  MI3->addOperand(*MF, MachineOperand::CreateReg(Reg1, /*isDef*/ false));
+  MI3->addOperand(*MF, MachineOperand::CreateMBB(MBB1));
+  MI3->addOperand(*MF, MachineOperand::CreateReg(Reg2, /*isDef*/ false));
+  MI3->addOperand(*MF, MachineOperand::CreateMBB(MBB2));
+  MBB3->insert(MBB3->end(), MI3);
+
+  SparseLiveVariables LV;
+  LV.runOnMachineFunction(*MF);
+
+  // For PHI nodes, Reg1 and Reg2 should be LiveOut of their respective
+  // predecessors, but neither should be considered LiveIn to MBB3.
+  EXPECT_TRUE(LV.getLiveOutSet(MBB1).test(Reg1.id()));
+  EXPECT_FALSE(LV.getLiveInSet(MBB3).test(Reg1.id()));
+
+  EXPECT_TRUE(LV.getLiveOutSet(MBB2).test(Reg2.id()));
+  EXPECT_FALSE(LV.getLiveInSet(MBB3).test(Reg2.id()));
+}
+
+TEST(SparseLiveVariablesTest, TrackerAPI) {
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
+  auto MBB = MF->CreateMachineBasicBlock();
+  MF->push_back(MBB);
+
+  MCInstrDesc MCID = {100, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+
+  MCRegisterClass MRC{
+      0, 0, 0, 0, 0, 0, 0, 0, /*Allocatable=*/true, /*BaseClass=*/true};
+  TargetRegisterClass RC{&MRC, 0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0};
+  MachineRegisterInfo &MRI = MF->getRegInfo();
+
+  Register Reg0 = MRI.createVirtualRegister(&RC);
+  Register Reg1 = MRI.createVirtualRegister(&RC);
+
+  // MI1: %0 = OP
+  MachineInstr *MI1 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI1->addOperand(*MF, MachineOperand::CreateReg(Reg0, /*isDef*/ true));
+  MBB->insert(MBB->end(), MI1);
+
+  // MI2: %1 = OP %0
+  MachineInstr *MI2 = MF->CreateMachineInstr(MCID, DebugLoc());
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg1, /*isDef*/ true));
+  MI2->addOperand(*MF, MachineOperand::CreateReg(Reg0, /*isDef*/ false));
+  MBB->insert(MBB->end(), MI2);
+
+  SparseBitVector<> LiveOut;
+  // Initialize Tracker with empty LiveOut
+  SparseLiveVariables::LivenessTracker Tracker(LiveOut, &MRI);
+
+  EXPECT_FALSE(Tracker.isLive(Reg0));
+  EXPECT_FALSE(Tracker.isLive(Reg1));
+
+  Tracker.stepBackward(*MI2);
+
+  // After stepping backward over MI2, Reg1 is killed (def'd), and Reg0 becomes
+  // live (used)
+  EXPECT_TRUE(Tracker.isLive(Reg0));
+  EXPECT_FALSE(Tracker.isLive(Reg1));
+
+  Tracker.stepBackward(*MI1);
+
+  // After stepping backward over MI1, Reg0 is killed (def'd).
+  EXPECT_FALSE(Tracker.isLive(Reg0));
+  EXPECT_FALSE(Tracker.isLive(Reg1));
+}
+
 } // end namespace



More information about the llvm-commits mailing list