xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AMDGPU/AMDGPUMarkLastScratchLoad.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
1*7a6dacacSDimitry Andric //===-- AMDGPUMarkLastScratchLoad.cpp -------------------------------------===//
2*7a6dacacSDimitry Andric //
3*7a6dacacSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*7a6dacacSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*7a6dacacSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*7a6dacacSDimitry Andric //
7*7a6dacacSDimitry Andric //===----------------------------------------------------------------------===//
8*7a6dacacSDimitry Andric //
9*7a6dacacSDimitry Andric // Mark scratch load/spill instructions which are guaranteed to be the last time
10*7a6dacacSDimitry Andric // this scratch slot is used so it can be evicted from caches.
11*7a6dacacSDimitry Andric //
12*7a6dacacSDimitry Andric // TODO: Handle general stack accesses not just spilling.
13*7a6dacacSDimitry Andric //
14*7a6dacacSDimitry Andric //===----------------------------------------------------------------------===//
15*7a6dacacSDimitry Andric 
16*7a6dacacSDimitry Andric #include "AMDGPU.h"
17*7a6dacacSDimitry Andric #include "GCNSubtarget.h"
18*7a6dacacSDimitry Andric #include "llvm/CodeGen/LiveIntervals.h"
19*7a6dacacSDimitry Andric #include "llvm/CodeGen/LiveStacks.h"
20*7a6dacacSDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
21*7a6dacacSDimitry Andric 
22*7a6dacacSDimitry Andric using namespace llvm;
23*7a6dacacSDimitry Andric 
24*7a6dacacSDimitry Andric #define DEBUG_TYPE "amdgpu-mark-last-scratch-load"
25*7a6dacacSDimitry Andric 
26*7a6dacacSDimitry Andric namespace {
27*7a6dacacSDimitry Andric 
28*7a6dacacSDimitry Andric class AMDGPUMarkLastScratchLoad : public MachineFunctionPass {
29*7a6dacacSDimitry Andric private:
30*7a6dacacSDimitry Andric   LiveStacks *LS = nullptr;
31*7a6dacacSDimitry Andric   LiveIntervals *LIS = nullptr;
32*7a6dacacSDimitry Andric   SlotIndexes *SI = nullptr;
33*7a6dacacSDimitry Andric   const SIInstrInfo *SII = nullptr;
34*7a6dacacSDimitry Andric 
35*7a6dacacSDimitry Andric public:
36*7a6dacacSDimitry Andric   static char ID;
37*7a6dacacSDimitry Andric 
38*7a6dacacSDimitry Andric   AMDGPUMarkLastScratchLoad() : MachineFunctionPass(ID) {
39*7a6dacacSDimitry Andric     initializeAMDGPUMarkLastScratchLoadPass(*PassRegistry::getPassRegistry());
40*7a6dacacSDimitry Andric   }
41*7a6dacacSDimitry Andric 
42*7a6dacacSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
43*7a6dacacSDimitry Andric 
44*7a6dacacSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
45*7a6dacacSDimitry Andric     AU.addRequired<SlotIndexes>();
46*7a6dacacSDimitry Andric     AU.addRequired<LiveIntervals>();
47*7a6dacacSDimitry Andric     AU.addRequired<LiveStacks>();
48*7a6dacacSDimitry Andric     AU.setPreservesAll();
49*7a6dacacSDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
50*7a6dacacSDimitry Andric   }
51*7a6dacacSDimitry Andric 
52*7a6dacacSDimitry Andric   StringRef getPassName() const override {
53*7a6dacacSDimitry Andric     return "AMDGPU Mark Last Scratch Load";
54*7a6dacacSDimitry Andric   }
55*7a6dacacSDimitry Andric };
56*7a6dacacSDimitry Andric 
57*7a6dacacSDimitry Andric } // end anonymous namespace
58*7a6dacacSDimitry Andric 
59*7a6dacacSDimitry Andric bool AMDGPUMarkLastScratchLoad::runOnMachineFunction(MachineFunction &MF) {
60*7a6dacacSDimitry Andric   if (skipFunction(MF.getFunction()))
61*7a6dacacSDimitry Andric     return false;
62*7a6dacacSDimitry Andric 
63*7a6dacacSDimitry Andric   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
64*7a6dacacSDimitry Andric   if (ST.getGeneration() < AMDGPUSubtarget::GFX12)
65*7a6dacacSDimitry Andric     return false;
66*7a6dacacSDimitry Andric 
67*7a6dacacSDimitry Andric   LS = &getAnalysis<LiveStacks>();
68*7a6dacacSDimitry Andric   LIS = &getAnalysis<LiveIntervals>();
69*7a6dacacSDimitry Andric   SI = &getAnalysis<SlotIndexes>();
70*7a6dacacSDimitry Andric   SII = ST.getInstrInfo();
71*7a6dacacSDimitry Andric   SlotIndexes &Slots = *LIS->getSlotIndexes();
72*7a6dacacSDimitry Andric 
73*7a6dacacSDimitry Andric   const unsigned NumSlots = LS->getNumIntervals();
74*7a6dacacSDimitry Andric   if (NumSlots == 0) {
75*7a6dacacSDimitry Andric     LLVM_DEBUG(dbgs() << "No live slots, skipping\n");
76*7a6dacacSDimitry Andric     return false;
77*7a6dacacSDimitry Andric   }
78*7a6dacacSDimitry Andric 
79*7a6dacacSDimitry Andric   LLVM_DEBUG(dbgs() << LS->getNumIntervals() << " intervals\n");
80*7a6dacacSDimitry Andric 
81*7a6dacacSDimitry Andric   bool Changed = false;
82*7a6dacacSDimitry Andric 
83*7a6dacacSDimitry Andric   for (auto &[SS, LI] : *LS) {
84*7a6dacacSDimitry Andric     for (const LiveRange::Segment &Segment : LI.segments) {
85*7a6dacacSDimitry Andric 
86*7a6dacacSDimitry Andric       // Ignore segments that run to the end of basic block because in this case
87*7a6dacacSDimitry Andric       // slot is still live at the end of it.
88*7a6dacacSDimitry Andric       if (Segment.end.isBlock())
89*7a6dacacSDimitry Andric         continue;
90*7a6dacacSDimitry Andric 
91*7a6dacacSDimitry Andric       const int FrameIndex = Register::stackSlot2Index(LI.reg());
92*7a6dacacSDimitry Andric       MachineInstr *LastLoad = nullptr;
93*7a6dacacSDimitry Andric 
94*7a6dacacSDimitry Andric       MachineInstr *MISegmentEnd = SI->getInstructionFromIndex(Segment.end);
95*7a6dacacSDimitry Andric 
96*7a6dacacSDimitry Andric       // If there is no instruction at this slot because it was deleted take the
97*7a6dacacSDimitry Andric       // instruction from the next slot.
98*7a6dacacSDimitry Andric       if (!MISegmentEnd) {
99*7a6dacacSDimitry Andric         SlotIndex NextSlot = Slots.getNextNonNullIndex(Segment.end);
100*7a6dacacSDimitry Andric         MISegmentEnd = SI->getInstructionFromIndex(NextSlot);
101*7a6dacacSDimitry Andric       }
102*7a6dacacSDimitry Andric 
103*7a6dacacSDimitry Andric       MachineInstr *MISegmentStart = SI->getInstructionFromIndex(Segment.start);
104*7a6dacacSDimitry Andric       MachineBasicBlock *BB = MISegmentEnd->getParent();
105*7a6dacacSDimitry Andric 
106*7a6dacacSDimitry Andric       // Start iteration backwards from segment end until the start of basic
107*7a6dacacSDimitry Andric       // block or start of segment if it is in the same basic block.
108*7a6dacacSDimitry Andric       auto End = BB->rend();
109*7a6dacacSDimitry Andric       if (MISegmentStart && MISegmentStart->getParent() == BB)
110*7a6dacacSDimitry Andric         End = MISegmentStart->getReverseIterator();
111*7a6dacacSDimitry Andric 
112*7a6dacacSDimitry Andric       for (auto MI = MISegmentEnd->getReverseIterator(); MI != End; ++MI) {
113*7a6dacacSDimitry Andric         int LoadFI = 0;
114*7a6dacacSDimitry Andric 
115*7a6dacacSDimitry Andric         if (SII->isLoadFromStackSlot(*MI, LoadFI) && LoadFI == FrameIndex) {
116*7a6dacacSDimitry Andric           LastLoad = &*MI;
117*7a6dacacSDimitry Andric           break;
118*7a6dacacSDimitry Andric         }
119*7a6dacacSDimitry Andric       }
120*7a6dacacSDimitry Andric 
121*7a6dacacSDimitry Andric       if (LastLoad && !LastLoad->memoperands_empty()) {
122*7a6dacacSDimitry Andric         MachineMemOperand *MMO = *LastLoad->memoperands_begin();
123*7a6dacacSDimitry Andric         MMO->setFlags(MOLastUse);
124*7a6dacacSDimitry Andric         Changed = true;
125*7a6dacacSDimitry Andric         LLVM_DEBUG(dbgs() << "  Found last load: " << *LastLoad);
126*7a6dacacSDimitry Andric       }
127*7a6dacacSDimitry Andric     }
128*7a6dacacSDimitry Andric   }
129*7a6dacacSDimitry Andric 
130*7a6dacacSDimitry Andric   return Changed;
131*7a6dacacSDimitry Andric }
132*7a6dacacSDimitry Andric 
133*7a6dacacSDimitry Andric char AMDGPUMarkLastScratchLoad::ID = 0;
134*7a6dacacSDimitry Andric 
135*7a6dacacSDimitry Andric char &llvm::AMDGPUMarkLastScratchLoadID = AMDGPUMarkLastScratchLoad::ID;
136*7a6dacacSDimitry Andric 
137*7a6dacacSDimitry Andric INITIALIZE_PASS_BEGIN(AMDGPUMarkLastScratchLoad, DEBUG_TYPE,
138*7a6dacacSDimitry Andric                       "AMDGPU Mark last scratch load", false, false)
139*7a6dacacSDimitry Andric INITIALIZE_PASS_DEPENDENCY(SlotIndexes)
140*7a6dacacSDimitry Andric INITIALIZE_PASS_DEPENDENCY(LiveStacks)
141*7a6dacacSDimitry Andric INITIALIZE_PASS_END(AMDGPUMarkLastScratchLoad, DEBUG_TYPE,
142*7a6dacacSDimitry Andric                     "AMDGPU Mark last scratch load", false, false)
143