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

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 24 10:38:46 PST 2025


================
@@ -0,0 +1,598 @@
+//===- 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 "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>
+#include <unordered_map>
+
+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(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);
+
+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
+/// 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(bool PreRegAlloc)
+      : MachineFunctionPass(ID), 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;
+
+  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;
+
+  /// 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(bool PreRegAlloc) {
+  return new RISCVLiveVariables(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++));
+
+    // 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);
+
+        // Also handle sub-registers for physical registers
+        if (Reg.isPhysical()) {
+          for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
+               SubRegs.isValid(); ++SubRegs) {
+            if (Info.Gen.find(*SubRegs) == Info.Gen.end()) {
+              Info.Use.insert(*SubRegs);
+            }
+          }
+        }
+      }
+    }
+
+    // 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);
+  }
+
+  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
----------------
arsenm wrote:

Liveness should be done in reverse 

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


More information about the llvm-commits mailing list