[llvm] [RISCV64] liveness analysis (PR #167454)

via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 18 19:50:24 PDT 2026


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

>From 0a1a47f691f0ce11abcce56f6e8e22ea8c15d98e 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/26] [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 dc94c246988aec0a7587278c16b92d42b27e1488 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/26] 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 1e1c5fa259beb97883a110f1a564268c37014e5d 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/26] 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 59a21e5dbaae75347783d0d9adc1ba3fb9b0eca1 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/26] 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 86c96e7bd8d90d232caa9fe9192dae7ed48554cd 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/26] 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 398b075f7e8bd10c5cc161422f4382042e147a13 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/26] 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 fc3352b86a47ad7c32e1b8ec8c402f05095dd842 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/26] 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 d7f5c89354ebfe55a1bd89c2f21371b4dd999bc3 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/26] 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 73e84abeaba0e7fc3b4a85eeed46284a4dbf39ae 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/26] 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 faaad27518e21e6218cf6c88eba3523fd237a17e 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/26] 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 4f84a8e91f2d52817026afefe20ee261d187e187 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/26] 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 bd411d1f8555764de7475191ca4e891b1fcde106 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/26] 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 46cd8445cead1952937b2c1d62e4e32bcb556a32 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/26] 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 38598c4c85d3b8a41d40603e947dce901c3d6d23 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/26] 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 d0f2bfae5ebf4a15ecbede8ff1324d1ec9263760 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/26] 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 fa22f916584c905f2c0acfcc10570493dc6672c0 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/26] 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 de8c07d43c392bed9b5906454f968aa41a9fd2a8 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/26] 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 4a2204ff24ed656b76981158a70562b90ee99e24 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/26] 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 48bc7b4fea7f7ec3984c10d70628885f1d5bcedc 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/26] 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 a66aafdc5d6c395f55df1bd5f525e9110513baf0 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/26] 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 e0c4c71ad3a08d29d95fb673497c1c0c1f85d246 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/26] 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 f0977f6d96d900900ab0e01197c7439b2654c064 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/26] 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 6595264c2fc4dc74559975f12afe53f8393ce347 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/26] 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 d9cfe065ffbec..470efcc4b565f 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 1a224e4022649ef0245215e79bc6c5ed326f5402 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/26] 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 b50d21dda103c46f515a4b01e07056bfe880283e 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/26] 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 7f32e059a313bed6671e2cb67164f47253f44a7d 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/26] Bug fixes triggered by test

---
 llvm/include/llvm/CodeGen/Passes.h            |   4 +-
 .../llvm/CodeGen/SparseLiveVariables.h        |   5 +
 llvm/lib/CodeGen/MachineLICM.cpp              |   6 +-
 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/X86/opt-pipeline.ll         |   2 +
 7 files changed, 186 insertions(+), 176 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h
index 470efcc4b565f..0437a51400b7a 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..25696fe0c53f7 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);
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/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/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



More information about the llvm-commits mailing list