Skip to content

Commit

Permalink
[ReachingDefAnalysis] Extend the analysis to stack objects.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mgudim authored and Mikhail Gudim committed Jan 8, 2025
1 parent fe162be commit fd173d6
Show file tree
Hide file tree
Showing 4 changed files with 289 additions and 3 deletions.
13 changes: 13 additions & 0 deletions llvm/include/llvm/CodeGen/ReachingDefAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand All @@ -158,6 +168,7 @@ class ReachingDefAnalysis : public MachineFunctionPass {
MachineFunctionPass::getAnalysisUsage(AU);
}

void printAllReachingDefs(MachineFunction &MF);
bool runOnMachineFunction(MachineFunction &MF) override;

MachineFunctionProperties getRequiredProperties() const override {
Expand All @@ -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, MCRegister Reg) const;

/// Return whether A and B use the same def of Reg.
Expand Down Expand Up @@ -308,6 +320,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, MCRegister Reg) const;
};

Expand Down
98 changes: 95 additions & 3 deletions llvm/lib/CodeGen/ReachingDefAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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)
Expand Down Expand Up @@ -48,12 +54,25 @@ static bool isValidRegDefOf(const MachineOperand &MO, MCRegister 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;

Expand Down Expand Up @@ -126,6 +145,13 @@ void ReachingDefAnalysis::processDefs(MachineInstr *MI) {
"Unexpected basic block number.");

for (auto &MO : MI->operands()) {
if (MO.isFI()) {
int FrameIndex = MO.getIndex();
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())) {
Expand Down Expand Up @@ -209,19 +235,62 @@ 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();
Reg = Register::index2StackSlot(FrameIndex);
} else if (MO.isReg()) {
if (MO.isDef())
continue;
Reg = MO.getReg();
if (Reg == MCRegister::NoRegister)
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;
}

void ReachingDefAnalysis::releaseMemory() {
// Clear the internal vectors.
MBBOutRegsInfos.clear();
MBBReachingDefs.clear();
MBBFrameObjsReachingDefs.clear();
InstIds.clear();
LiveRegs.clear();
}
Expand All @@ -234,7 +303,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;
Expand Down Expand Up @@ -269,6 +341,19 @@ int ReachingDefAnalysis::getReachingDef(MachineInstr *MI,
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)
Expand Down Expand Up @@ -422,7 +507,7 @@ void ReachingDefAnalysis::getLiveOuts(MachineBasicBlock *MBB, MCRegister 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))
Expand Down Expand Up @@ -505,7 +590,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();
Expand All @@ -525,14 +610,21 @@ MachineInstr *ReachingDefAnalysis::getLocalLiveOutMIDef(MachineBasicBlock *MBB,
MCRegister 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;

int Def = getReachingDef(&*Last, Reg);

if (Register::isStackSlot(Reg)) {
int FrameIndex = Register::stackSlot2Index(Reg);
if (isFIDef(*Last, FrameIndex, TII))
return &*Last;
}

for (auto &MO : Last->operands())
if (isValidRegDefOf(MO, Reg, TRI))
return &*Last;
Expand Down
151 changes: 151 additions & 0 deletions llvm/test/CodeGen/RISCV/rda-stack.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# RUN: llc %s -mtriple=riscv64 -run-pass=reaching-deps-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
...
Loading

0 comments on commit fd173d6

Please sign in to comment.