[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