Skip to content

[ReachingDefAnalysis] Extend the analysis to stack objects. #118097

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 =
DenseMap<unsigned, DenseMap<int, 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, Register Reg) const;

/// Return whether A and B use the same def of Reg.
Expand Down Expand Up @@ -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;
};

Expand Down
103 changes: 100 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,6 +54,16 @@ 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() &&
Expand Down Expand Up @@ -126,6 +142,22 @@ 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;
if (MBBFrameObjsReachingDefs.contains(MBBNumber)) {
auto Frame2InstrIdx = MBBFrameObjsReachingDefs[MBBNumber];
if (Frame2InstrIdx.count(FrameIndex - ObjectIndexBegin) > 0)
Frame2InstrIdx[FrameIndex - ObjectIndexBegin].push_back(CurInstr);
else
Frame2InstrIdx[FrameIndex - ObjectIndexBegin] = {CurInstr};
} else {
MBBFrameObjsReachingDefs[MBBNumber] = {
{FrameIndex - ObjectIndexBegin, {CurInstr}}};
}
}
if (!isValidRegDef(MO))
continue;
for (MCRegUnit Unit : TRI->regunits(MO.getReg().asMCReg())) {
Expand Down Expand Up @@ -209,19 +241,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();
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;
}

void ReachingDefAnalysis::releaseMemory() {
// Clear the internal vectors.
MBBOutRegsInfos.clear();
MBBReachingDefs.clear();
MBBFrameObjsReachingDefs.clear();
InstIds.clear();
LiveRegs.clear();
}
Expand All @@ -234,6 +309,8 @@ void ReachingDefAnalysis::reset() {

void ReachingDefAnalysis::init() {
NumRegUnits = TRI->getNumRegUnits();
NumStackObjects = MF->getFrameInfo().getNumObjects();
ObjectIndexBegin = MF->getFrameInfo().getObjectIndexBegin();
MBBReachingDefs.init(MF->getNumBlockIDs());
// Initialize the MBBOutRegsInfos
MBBOutRegsInfos.resize(MF->getNumBlockIDs());
Expand Down Expand Up @@ -268,6 +345,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.lookup(MBBNumber).lookup(
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 @@ -419,7 +509,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))
Expand Down Expand Up @@ -500,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 @@ -520,14 +610,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;
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-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
...
Loading
Loading