From fd173d66b2a33a1a1a2f1b813fc910fb0be2e83e Mon Sep 17 00:00:00 2001 From: Mikhail Gudim 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 | 98 +++++++++++- llvm/test/CodeGen/RISCV/rda-stack.mir | 151 ++++++++++++++++++ llvm/test/CodeGen/SystemZ/rda-stack-copy.mir | 30 ++++ 4 files changed, 289 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 0c1e707e4ecbb0..a8fb31bd6eade0 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 InstIds; MBBReachingDefsInfo MBBReachingDefs; + using MBBFrameObjsReachingDefsInfo = + std::vector>>; + // 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, MCRegister Reg) const; /// Return whether A and B use the same def of Reg. @@ -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; }; diff --git a/llvm/lib/CodeGen/ReachingDefAnalysis.cpp b/llvm/lib/CodeGen/ReachingDefAnalysis.cpp index 3ab6315f9c8ee2..5e8ae9edb8e087 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 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, 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; @@ -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())) { @@ -209,12 +235,54 @@ void ReachingDefAnalysis::processBasicBlock( leaveBasicBlock(MBB); } +void ReachingDefAnalysis::printAllReachingDefs(MachineFunction &MF) { + dbgs() << "RDA results for " << MF.getName() << "\n"; + int Num = 0; + DenseMap InstToNumMap; + SmallPtrSet 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; } @@ -222,6 +290,7 @@ void ReachingDefAnalysis::releaseMemory() { // Clear the internal vectors. MBBOutRegsInfos.clear(); MBBReachingDefs.clear(); + MBBFrameObjsReachingDefs.clear(); InstIds.clear(); LiveRegs.clear(); } @@ -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; @@ -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) @@ -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)) @@ -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(); @@ -525,7 +610,7 @@ 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(); @@ -533,6 +618,13 @@ MachineInstr *ReachingDefAnalysis::getLocalLiveOutMIDef(MachineBasicBlock *MBB, 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; diff --git a/llvm/test/CodeGen/RISCV/rda-stack.mir b/llvm/test/CodeGen/RISCV/rda-stack.mir new file mode 100644 index 00000000000000..2f7b546526f241 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rda-stack.mir @@ -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 +... 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..e8ea6d9cb8cd96 --- /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-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: '' } + - { 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 + +...