[llvm] [ReachingDefAnalysis] Extend the analysis to stack objects. (PR #118097)
Mikhail Gudim via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 27 06:18:43 PST 2025
https://github.com/mgudim updated https://github.com/llvm/llvm-project/pull/118097
>From 799e1c26fe17546556093edf76d8255dff1059d6 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Fri, 29 Nov 2024 09:26:12 -0500
Subject: [PATCH] [ReachingDefAnalysis] Extend the analysis to stack objects.
We track definitions of stack objects, the implementation is identical
to tracking of registers.
Also, added printing of all found reaching definitions for testing
purposes.
---
.../llvm/CodeGen/ReachingDefAnalysis.h | 13 ++
llvm/lib/CodeGen/ReachingDefAnalysis.cpp | 99 +++++++++++-
llvm/test/CodeGen/RISCV/rda-stack.mir | 151 ++++++++++++++++++
llvm/test/CodeGen/SystemZ/rda-stack-copy.mir | 30 ++++
4 files changed, 290 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/CodeGen/RISCV/rda-stack.mir
create mode 100644 llvm/test/CodeGen/SystemZ/rda-stack-copy.mir
diff --git a/llvm/include/llvm/CodeGen/ReachingDefAnalysis.h b/llvm/include/llvm/CodeGen/ReachingDefAnalysis.h
index 2e976a88b4cea1..7b6197345d4ed3 100644
--- a/llvm/include/llvm/CodeGen/ReachingDefAnalysis.h
+++ b/llvm/include/llvm/CodeGen/ReachingDefAnalysis.h
@@ -114,8 +114,11 @@ class ReachingDefAnalysis : public MachineFunctionPass {
private:
MachineFunction *MF = nullptr;
const TargetRegisterInfo *TRI = nullptr;
+ const TargetInstrInfo *TII = nullptr;
LoopTraversal::TraversalOrder TraversedMBBOrder;
unsigned NumRegUnits = 0;
+ unsigned NumStackObjects = 0;
+ int ObjectIndexBegin = 0;
/// Instruction that defined each register, relative to the beginning of the
/// current basic block. When a LiveRegsDefInfo is used to represent a
/// live-out register, this value is relative to the end of the basic block,
@@ -138,6 +141,13 @@ class ReachingDefAnalysis : public MachineFunctionPass {
DenseMap<MachineInstr *, int> InstIds;
MBBReachingDefsInfo MBBReachingDefs;
+ using MBBFrameObjsReachingDefsInfo =
+ std::vector<std::vector<SmallVector<int>>>;
+ // MBBFrameObjsReachingDefs[i][j] is a list of instruction indices (relative
+ // to begining of MBB) that define frame index (j +
+ // MF->getFrameInfo().getObjectIndexBegin()) in MBB i. This is used in
+ // answering reaching definition queries.
+ MBBFrameObjsReachingDefsInfo MBBFrameObjsReachingDefs;
/// Default values are 'nothing happened a long time ago'.
const int ReachingDefDefaultVal = -(1 << 21);
@@ -158,6 +168,7 @@ class ReachingDefAnalysis : public MachineFunctionPass {
MachineFunctionPass::getAnalysisUsage(AU);
}
+ void printAllReachingDefs(MachineFunction &MF);
bool runOnMachineFunction(MachineFunction &MF) override;
MachineFunctionProperties getRequiredProperties() const override {
@@ -177,6 +188,7 @@ class ReachingDefAnalysis : public MachineFunctionPass {
/// Provides the instruction id of the closest reaching def instruction of
/// Reg that reaches MI, relative to the begining of MI's basic block.
+ // Note that Reg may represent a stack slot.
int getReachingDef(MachineInstr *MI, Register Reg) const;
/// Return whether A and B use the same def of Reg.
@@ -305,6 +317,7 @@ class ReachingDefAnalysis : public MachineFunctionPass {
/// Provides the instruction of the closest reaching def instruction of
/// Reg that reaches MI, relative to the begining of MI's basic block.
+ // Note that Reg may represent a stack slot.
MachineInstr *getReachingLocalMIDef(MachineInstr *MI, Register Reg) const;
};
diff --git a/llvm/lib/CodeGen/ReachingDefAnalysis.cpp b/llvm/lib/CodeGen/ReachingDefAnalysis.cpp
index 9459904d56e4c3..fa1e97957a748c 100644
--- a/llvm/lib/CodeGen/ReachingDefAnalysis.cpp
+++ b/llvm/lib/CodeGen/ReachingDefAnalysis.cpp
@@ -10,6 +10,8 @@
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/CodeGen/LiveRegUnits.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Support/Debug.h"
@@ -18,6 +20,10 @@ using namespace llvm;
#define DEBUG_TYPE "reaching-defs-analysis"
+static cl::opt<bool> PrintAllReachingDefs("print-all-reaching-defs", cl::Hidden,
+ cl::desc("Used for test purpuses"),
+ cl::Hidden);
+
char ReachingDefAnalysis::ID = 0;
INITIALIZE_PASS(ReachingDefAnalysis, DEBUG_TYPE, "ReachingDefAnalysis", false,
true)
@@ -48,12 +54,25 @@ static bool isValidRegDefOf(const MachineOperand &MO, Register Reg,
return TRI->regsOverlap(MO.getReg(), Reg);
}
+static bool isFIDef(const MachineInstr &MI, int FrameIndex,
+ const TargetInstrInfo *TII) {
+ int DefFrameIndex = 0;
+ int SrcFrameIndex = 0;
+ if (TII->isStoreToStackSlot(MI, DefFrameIndex) ||
+ TII->isStackSlotCopy(MI, DefFrameIndex, SrcFrameIndex)) {
+ return DefFrameIndex == FrameIndex;
+ }
+ return false;
+}
+
void ReachingDefAnalysis::enterBasicBlock(MachineBasicBlock *MBB) {
unsigned MBBNumber = MBB->getNumber();
assert(MBBNumber < MBBReachingDefs.numBlockIDs() &&
"Unexpected basic block number.");
MBBReachingDefs.startBasicBlock(MBBNumber, NumRegUnits);
+ MBBFrameObjsReachingDefs[MBBNumber].resize(NumStackObjects, {-1});
+
// Reset instruction counter in each basic block.
CurInstr = 0;
@@ -126,6 +145,14 @@ void ReachingDefAnalysis::processDefs(MachineInstr *MI) {
"Unexpected basic block number.");
for (auto &MO : MI->operands()) {
+ if (MO.isFI()) {
+ int FrameIndex = MO.getIndex();
+ assert(FrameIndex >= 0 && "Can't handle negative frame indicies yet!");
+ if (!isFIDef(*MI, FrameIndex, TII))
+ continue;
+ MBBFrameObjsReachingDefs[MBBNumber][FrameIndex - ObjectIndexBegin]
+ .push_back(CurInstr);
+ }
if (!isValidRegDef(MO))
continue;
for (MCRegUnit Unit : TRI->regunits(MO.getReg().asMCReg())) {
@@ -209,12 +236,54 @@ void ReachingDefAnalysis::processBasicBlock(
leaveBasicBlock(MBB);
}
+void ReachingDefAnalysis::printAllReachingDefs(MachineFunction &MF) {
+ dbgs() << "RDA results for " << MF.getName() << "\n";
+ int Num = 0;
+ DenseMap<MachineInstr *, int> InstToNumMap;
+ SmallPtrSet<MachineInstr *, 2> Defs;
+ for (MachineBasicBlock &MBB : MF) {
+ for (MachineInstr &MI : MBB) {
+ for (MachineOperand &MO : MI.operands()) {
+ Register Reg;
+ if (MO.isFI()) {
+ int FrameIndex = MO.getIndex();
+ assert(FrameIndex >= 0 &&
+ "Can't handle negative frame indicies yet!");
+ Reg = Register::index2StackSlot(FrameIndex);
+ } else if (MO.isReg()) {
+ if (MO.isDef())
+ continue;
+ Reg = MO.getReg();
+ if (!Reg.isValid())
+ continue;
+ } else
+ continue;
+ Defs.clear();
+ getGlobalReachingDefs(&MI, Reg, Defs);
+ MO.print(dbgs(), TRI);
+ dbgs() << ":{ ";
+ for (MachineInstr *Def : Defs)
+ dbgs() << InstToNumMap[Def] << " ";
+ dbgs() << "}\n";
+ }
+ dbgs() << Num << ": " << MI << "\n";
+ InstToNumMap[&MI] = Num;
+ ++Num;
+ }
+ }
+}
+
bool ReachingDefAnalysis::runOnMachineFunction(MachineFunction &mf) {
MF = &mf;
TRI = MF->getSubtarget().getRegisterInfo();
+ const TargetSubtargetInfo &STI = MF->getSubtarget();
+ TRI = STI.getRegisterInfo();
+ TII = STI.getInstrInfo();
LLVM_DEBUG(dbgs() << "********** REACHING DEFINITION ANALYSIS **********\n");
init();
traverse();
+ if (PrintAllReachingDefs)
+ printAllReachingDefs(*MF);
return false;
}
@@ -222,6 +291,7 @@ void ReachingDefAnalysis::releaseMemory() {
// Clear the internal vectors.
MBBOutRegsInfos.clear();
MBBReachingDefs.clear();
+ MBBFrameObjsReachingDefs.clear();
InstIds.clear();
LiveRegs.clear();
}
@@ -234,7 +304,10 @@ void ReachingDefAnalysis::reset() {
void ReachingDefAnalysis::init() {
NumRegUnits = TRI->getNumRegUnits();
+ NumStackObjects = MF->getFrameInfo().getNumObjects();
+ ObjectIndexBegin = MF->getFrameInfo().getObjectIndexBegin();
MBBReachingDefs.init(MF->getNumBlockIDs());
+ MBBFrameObjsReachingDefs.resize(MF->getNumBlockIDs());
// Initialize the MBBOutRegsInfos
MBBOutRegsInfos.resize(MF->getNumBlockIDs());
LoopTraversal Traversal;
@@ -268,6 +341,19 @@ int ReachingDefAnalysis::getReachingDef(MachineInstr *MI, Register Reg) const {
assert(MBBNumber < MBBReachingDefs.numBlockIDs() &&
"Unexpected basic block number.");
int LatestDef = ReachingDefDefaultVal;
+
+ if (Register::isStackSlot(Reg)) {
+ int FrameIndex = Register::stackSlot2Index(Reg);
+ for (int Def :
+ MBBFrameObjsReachingDefs[MBBNumber][FrameIndex - ObjectIndexBegin]) {
+ if (Def >= InstId)
+ break;
+ DefRes = Def;
+ }
+ LatestDef = std::max(LatestDef, DefRes);
+ return LatestDef;
+ }
+
for (MCRegUnit Unit : TRI->regunits(Reg)) {
for (int Def : MBBReachingDefs.defs(MBBNumber, Unit)) {
if (Def >= InstId)
@@ -419,7 +505,7 @@ void ReachingDefAnalysis::getLiveOuts(MachineBasicBlock *MBB, Register Reg,
VisitedBBs.insert(MBB);
LiveRegUnits LiveRegs(*TRI);
LiveRegs.addLiveOuts(*MBB);
- if (LiveRegs.available(Reg))
+ if (Register::isPhysicalRegister(Reg) && LiveRegs.available(Reg))
return;
if (auto *Def = getLocalLiveOutMIDef(MBB, Reg))
@@ -500,7 +586,7 @@ bool ReachingDefAnalysis::isReachingDefLiveOut(MachineInstr *MI,
MachineBasicBlock *MBB = MI->getParent();
LiveRegUnits LiveRegs(*TRI);
LiveRegs.addLiveOuts(*MBB);
- if (LiveRegs.available(Reg))
+ if (Register::isPhysicalRegister(Reg) && LiveRegs.available(Reg))
return false;
auto Last = MBB->getLastNonDebugInstr();
@@ -520,14 +606,21 @@ MachineInstr *ReachingDefAnalysis::getLocalLiveOutMIDef(MachineBasicBlock *MBB,
Register Reg) const {
LiveRegUnits LiveRegs(*TRI);
LiveRegs.addLiveOuts(*MBB);
- if (LiveRegs.available(Reg))
+ if (Register::isPhysicalRegister(Reg) && LiveRegs.available(Reg))
return nullptr;
auto Last = MBB->getLastNonDebugInstr();
if (Last == MBB->end())
return nullptr;
+ if (Register::isStackSlot(Reg)) {
+ int FrameIndex = Register::stackSlot2Index(Reg);
+ if (isFIDef(*Last, FrameIndex, TII))
+ return &*Last;
+ }
+
int Def = getReachingDef(&*Last, Reg);
+
for (auto &MO : Last->operands())
if (isValidRegDefOf(MO, Reg, TRI))
return &*Last;
diff --git a/llvm/test/CodeGen/RISCV/rda-stack.mir b/llvm/test/CodeGen/RISCV/rda-stack.mir
new file mode 100644
index 00000000000000..5f4974181c1cd5
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rda-stack.mir
@@ -0,0 +1,151 @@
+# RUN: llc %s -mtriple=riscv64 -run-pass=reaching-defs-analysis -print-all-reaching-defs -o - 2>&1 | FileCheck %s
+
+---
+name: test0
+tracksRegLiveness: true
+stack:
+ - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ ; CHECK-LABEL: RDA results for test0
+ ; CHECK-NEXT: %stack.0:{ }
+ ; CHECK-NEXT:0: $x10 = LD %stack.0, 0 :: (load (s64))
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: implicit $x10:{ 0 }
+ ; CHECK-NEXT:1: PseudoRET implicit $x10
+
+ bb.0.entry:
+ $x10 = LD %stack.0, 0 :: (load (s64))
+ PseudoRET implicit $x10
+
+...
+---
+name: test1
+tracksRegLiveness: true
+stack:
+ - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+ - { id: 1, name: '', type: default, offset: 0, size: 4, alignment: 4,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ ; CHECK-LABEL: RDA results for test1
+ ; CHECK-NEXT: %stack.0:{ }
+ ; CHECK-NEXT: 0: $x10 = LD %stack.0, 0 :: (load (s64))
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: %stack.1:{ }
+ ; CHECK-NEXT: 1: $x11 = LD %stack.1, 0 :: (load (s64))
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: $x10:{ 0 }
+ ; CHECK-NEXT: $x11:{ 1 }
+ ; CHECK-NEXT: 2: $x10 = ADD $x10, $x11
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: implicit $x10:{ 2 }
+ ; CHECK-NEXT: 3: PseudoRET implicit $x10
+
+ bb.0.entry:
+ $x10 = LD %stack.0, 0 :: (load (s64))
+ $x11 = LD %stack.1, 0 :: (load (s64))
+ $x10 = ADD $x10, $x11
+ PseudoRET implicit $x10
+
+...
+---
+name: test2
+tracksRegLiveness: true
+stack:
+ - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+ - { id: 1, name: '', type: default, offset: 0, size: 4, alignment: 4,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ ; CHECK-LABEL: RDA results for test2
+ ; CHECK-NEXT: %stack.0:{ }
+ ; CHECK-NEXT: 0: $x10 = LD %stack.0, 0 :: (load (s64))
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: %stack.1:{ }
+ ; CHECK-NEXT: 1: $x11 = LD %stack.1, 0 :: (load (s64))
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: $x10:{ 0 }
+ ; CHECK-NEXT: $x11:{ 1 }
+ ; CHECK-NEXT: 2: $x10 = ADD $x10, $x11
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: $x10:{ 2 }
+ ; CHECK-NEXT: %stack.0:{ }
+ ; CHECK-NEXT: 3: SD $x10, %stack.0, 0 :: (store (s64))
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: %stack.0:{ 3 }
+ ; CHECK-NEXT: 4: $x10 = LD %stack.0, 0 :: (load (s64))
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: implicit $x10:{ 4 }
+ ; CHECK-NEXT: 5: PseudoRET implicit $x10
+
+ bb.0.entry:
+ $x10 = LD %stack.0, 0 :: (load (s64))
+ $x11 = LD %stack.1, 0 :: (load (s64))
+ $x10 = ADD $x10, $x11
+ SD $x10, %stack.0, 0 :: (store (s64))
+ $x10 = LD %stack.0, 0 :: (load (s64))
+ PseudoRET implicit $x10
+
+...
+---
+name: test3
+tracksRegLiveness: true
+stack:
+ - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ ; CHECK-LABEL: RDA results for test3
+ ; CHECK-NEXT: $x10:{ }
+ ; CHECK-NEXT: $x0:{ }
+ ; CHECK-NEXT: 0: BEQ $x10, $x0, %bb.2
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: $x10:{ }
+ ; CHECK-NEXT: 1: $x10 = ADDI $x10, 1
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: $x10:{ 1 }
+ ; CHECK-NEXT: %stack.0:{ }
+ ; CHECK-NEXT: 2: SD $x10, %stack.0, 0 :: (store (s64))
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: $x0:{ }
+ ; CHECK-NEXT: $x0:{ }
+ ; CHECK-NEXT: 3: BEQ $x0, $x0, %bb.3
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: $x10:{ 1 }
+ ; CHECK-NEXT: 4: $x10 = ADDI $x10, 2
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: $x10:{ 4 }
+ ; CHECK-NEXT: %stack.0:{ 2 }
+ ; CHECK-NEXT: 5: SD $x10, %stack.0, 0 :: (store (s64))
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: %stack.0:{ 2 5 }
+ ; CHECK-NEXT: 6: $x10 = LD %stack.0, 0 :: (load (s64))
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: implicit $x10:{ 6 }
+ ; CHECK-NEXT: 7: PseudoRET implicit $x10
+
+ bb.0.entry:
+ liveins: $x10
+ BEQ $x10, $x0, %bb.2
+
+ bb.1:
+ liveins: $x10
+ $x10 = ADDI $x10, 1
+ SD $x10, %stack.0, 0 :: (store (s64))
+ BEQ $x0, $x0, %bb.3
+
+ bb.2:
+ liveins: $x10
+ $x10 = ADDI $x10, 2
+ SD $x10, %stack.0, 0 :: (store (s64))
+
+ bb.3:
+ $x10 = LD %stack.0, 0 :: (load (s64))
+ PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/SystemZ/rda-stack-copy.mir b/llvm/test/CodeGen/SystemZ/rda-stack-copy.mir
new file mode 100644
index 00000000000000..a93b59324a8e52
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/rda-stack-copy.mir
@@ -0,0 +1,30 @@
+# RUN: llc %s -mtriple=s390x-linux-gnu -run-pass=reaching-defs-analysis -print-all-reaching-defs -o - 2>&1 | FileCheck %s
+
+---
+name: test0
+tracksRegLiveness: true
+stack:
+ - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+ - { id: 1, name: '', type: default, offset: 0, size: 4, alignment: 4,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ ; CHECK-LABEL: RDA results for test0
+ ; CHECK-NEXT: %stack.1:{ }
+ ; CHECK-NEXT: %stack.0:{ }
+ ; CHECK-NEXT: 0: MVC %stack.1, 0, 4, %stack.0, 0 :: (store (s32) into %stack.1), (load (s32) from %stack.0)
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: %stack.1:{ 0 }
+ ; CHECK-NEXT: 1: $r2l = L %stack.1, 0, $noreg
+ ; CHECK-EMPTY:
+ ; CHECK-NEXT: implicit $r2l:{ 1 }
+ ; CHECK-NEXT: 2: Return implicit $r2l
+
+ bb.0:
+ MVC %stack.1, 0 , 4, %stack.0, 0:: (store (s32) into %stack.1), (load (s32) from %stack.0)
+ $r2l = L %stack.1, 0, $noreg
+ Return implicit $r2l
+
+...
More information about the llvm-commits
mailing list