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

via llvm-commits llvm-commits at lists.llvm.org
Sat Dec 6 05:39:41 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;
----------------
hiraditya wrote:

Yeah we can do that as well, but wouldn't that require renumbering? I'm fine either way, lmk if you have a preference.

FWIW, the DenseMap here doesn't introduce non-determinism as there is no transformation that iterates upon this.

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


More information about the llvm-commits mailing list