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 + +...