xref: /src/contrib/llvm-project/llvm/lib/Target/AMDGPU/AMDGPUMarkLastScratchLoad.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
14df029ccSDimitry Andric //===-- AMDGPUMarkLastScratchLoad.cpp -------------------------------------===//
24df029ccSDimitry Andric //
34df029ccSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44df029ccSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
54df029ccSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64df029ccSDimitry Andric //
74df029ccSDimitry Andric //===----------------------------------------------------------------------===//
84df029ccSDimitry Andric //
94df029ccSDimitry Andric // Mark scratch load/spill instructions which are guaranteed to be the last time
104df029ccSDimitry Andric // this scratch slot is used so it can be evicted from caches.
114df029ccSDimitry Andric //
124df029ccSDimitry Andric // TODO: Handle general stack accesses not just spilling.
134df029ccSDimitry Andric //
144df029ccSDimitry Andric //===----------------------------------------------------------------------===//
154df029ccSDimitry Andric 
164df029ccSDimitry Andric #include "AMDGPU.h"
174df029ccSDimitry Andric #include "GCNSubtarget.h"
184df029ccSDimitry Andric #include "llvm/CodeGen/LiveIntervals.h"
194df029ccSDimitry Andric #include "llvm/CodeGen/LiveStacks.h"
204df029ccSDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
214df029ccSDimitry Andric 
224df029ccSDimitry Andric using namespace llvm;
234df029ccSDimitry Andric 
244df029ccSDimitry Andric #define DEBUG_TYPE "amdgpu-mark-last-scratch-load"
254df029ccSDimitry Andric 
264df029ccSDimitry Andric namespace {
274df029ccSDimitry Andric 
284df029ccSDimitry Andric class AMDGPUMarkLastScratchLoad : public MachineFunctionPass {
294df029ccSDimitry Andric private:
304df029ccSDimitry Andric   LiveStacks *LS = nullptr;
314df029ccSDimitry Andric   LiveIntervals *LIS = nullptr;
324df029ccSDimitry Andric   SlotIndexes *SI = nullptr;
334df029ccSDimitry Andric   const SIInstrInfo *SII = nullptr;
344df029ccSDimitry Andric 
354df029ccSDimitry Andric public:
364df029ccSDimitry Andric   static char ID;
374df029ccSDimitry Andric 
AMDGPUMarkLastScratchLoad()384df029ccSDimitry Andric   AMDGPUMarkLastScratchLoad() : MachineFunctionPass(ID) {
394df029ccSDimitry Andric     initializeAMDGPUMarkLastScratchLoadPass(*PassRegistry::getPassRegistry());
404df029ccSDimitry Andric   }
414df029ccSDimitry Andric 
424df029ccSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
434df029ccSDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const444df029ccSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
45ac9a064cSDimitry Andric     AU.addRequired<SlotIndexesWrapperPass>();
46ac9a064cSDimitry Andric     AU.addRequired<LiveIntervalsWrapperPass>();
474df029ccSDimitry Andric     AU.addRequired<LiveStacks>();
484df029ccSDimitry Andric     AU.setPreservesAll();
494df029ccSDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
504df029ccSDimitry Andric   }
514df029ccSDimitry Andric 
getPassName() const524df029ccSDimitry Andric   StringRef getPassName() const override {
534df029ccSDimitry Andric     return "AMDGPU Mark Last Scratch Load";
544df029ccSDimitry Andric   }
554df029ccSDimitry Andric };
564df029ccSDimitry Andric 
574df029ccSDimitry Andric } // end anonymous namespace
584df029ccSDimitry Andric 
runOnMachineFunction(MachineFunction & MF)594df029ccSDimitry Andric bool AMDGPUMarkLastScratchLoad::runOnMachineFunction(MachineFunction &MF) {
604df029ccSDimitry Andric   if (skipFunction(MF.getFunction()))
614df029ccSDimitry Andric     return false;
624df029ccSDimitry Andric 
634df029ccSDimitry Andric   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
644df029ccSDimitry Andric   if (ST.getGeneration() < AMDGPUSubtarget::GFX12)
654df029ccSDimitry Andric     return false;
664df029ccSDimitry Andric 
674df029ccSDimitry Andric   LS = &getAnalysis<LiveStacks>();
68ac9a064cSDimitry Andric   LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS();
69ac9a064cSDimitry Andric   SI = &getAnalysis<SlotIndexesWrapperPass>().getSI();
704df029ccSDimitry Andric   SII = ST.getInstrInfo();
714df029ccSDimitry Andric   SlotIndexes &Slots = *LIS->getSlotIndexes();
724df029ccSDimitry Andric 
734df029ccSDimitry Andric   const unsigned NumSlots = LS->getNumIntervals();
744df029ccSDimitry Andric   if (NumSlots == 0) {
754df029ccSDimitry Andric     LLVM_DEBUG(dbgs() << "No live slots, skipping\n");
764df029ccSDimitry Andric     return false;
774df029ccSDimitry Andric   }
784df029ccSDimitry Andric 
794df029ccSDimitry Andric   LLVM_DEBUG(dbgs() << LS->getNumIntervals() << " intervals\n");
804df029ccSDimitry Andric 
814df029ccSDimitry Andric   bool Changed = false;
824df029ccSDimitry Andric 
834df029ccSDimitry Andric   for (auto &[SS, LI] : *LS) {
844df029ccSDimitry Andric     for (const LiveRange::Segment &Segment : LI.segments) {
854df029ccSDimitry Andric 
864df029ccSDimitry Andric       // Ignore segments that run to the end of basic block because in this case
874df029ccSDimitry Andric       // slot is still live at the end of it.
884df029ccSDimitry Andric       if (Segment.end.isBlock())
894df029ccSDimitry Andric         continue;
904df029ccSDimitry Andric 
914df029ccSDimitry Andric       const int FrameIndex = Register::stackSlot2Index(LI.reg());
924df029ccSDimitry Andric       MachineInstr *LastLoad = nullptr;
934df029ccSDimitry Andric 
944df029ccSDimitry Andric       MachineInstr *MISegmentEnd = SI->getInstructionFromIndex(Segment.end);
954df029ccSDimitry Andric 
964df029ccSDimitry Andric       // If there is no instruction at this slot because it was deleted take the
974df029ccSDimitry Andric       // instruction from the next slot.
984df029ccSDimitry Andric       if (!MISegmentEnd) {
994df029ccSDimitry Andric         SlotIndex NextSlot = Slots.getNextNonNullIndex(Segment.end);
1004df029ccSDimitry Andric         MISegmentEnd = SI->getInstructionFromIndex(NextSlot);
1014df029ccSDimitry Andric       }
1024df029ccSDimitry Andric 
1034df029ccSDimitry Andric       MachineInstr *MISegmentStart = SI->getInstructionFromIndex(Segment.start);
1044df029ccSDimitry Andric       MachineBasicBlock *BB = MISegmentEnd->getParent();
1054df029ccSDimitry Andric 
1064df029ccSDimitry Andric       // Start iteration backwards from segment end until the start of basic
1074df029ccSDimitry Andric       // block or start of segment if it is in the same basic block.
1084df029ccSDimitry Andric       auto End = BB->rend();
1094df029ccSDimitry Andric       if (MISegmentStart && MISegmentStart->getParent() == BB)
1104df029ccSDimitry Andric         End = MISegmentStart->getReverseIterator();
1114df029ccSDimitry Andric 
1124df029ccSDimitry Andric       for (auto MI = MISegmentEnd->getReverseIterator(); MI != End; ++MI) {
1134df029ccSDimitry Andric         int LoadFI = 0;
1144df029ccSDimitry Andric 
1154df029ccSDimitry Andric         if (SII->isLoadFromStackSlot(*MI, LoadFI) && LoadFI == FrameIndex) {
1164df029ccSDimitry Andric           LastLoad = &*MI;
1174df029ccSDimitry Andric           break;
1184df029ccSDimitry Andric         }
1194df029ccSDimitry Andric       }
1204df029ccSDimitry Andric 
1214df029ccSDimitry Andric       if (LastLoad && !LastLoad->memoperands_empty()) {
1224df029ccSDimitry Andric         MachineMemOperand *MMO = *LastLoad->memoperands_begin();
1234df029ccSDimitry Andric         MMO->setFlags(MOLastUse);
1244df029ccSDimitry Andric         Changed = true;
1254df029ccSDimitry Andric         LLVM_DEBUG(dbgs() << "  Found last load: " << *LastLoad);
1264df029ccSDimitry Andric       }
1274df029ccSDimitry Andric     }
1284df029ccSDimitry Andric   }
1294df029ccSDimitry Andric 
1304df029ccSDimitry Andric   return Changed;
1314df029ccSDimitry Andric }
1324df029ccSDimitry Andric 
1334df029ccSDimitry Andric char AMDGPUMarkLastScratchLoad::ID = 0;
1344df029ccSDimitry Andric 
1354df029ccSDimitry Andric char &llvm::AMDGPUMarkLastScratchLoadID = AMDGPUMarkLastScratchLoad::ID;
1364df029ccSDimitry Andric 
1374df029ccSDimitry Andric INITIALIZE_PASS_BEGIN(AMDGPUMarkLastScratchLoad, DEBUG_TYPE,
1384df029ccSDimitry Andric                       "AMDGPU Mark last scratch load", false, false)
139ac9a064cSDimitry Andric INITIALIZE_PASS_DEPENDENCY(SlotIndexesWrapperPass)
1404df029ccSDimitry Andric INITIALIZE_PASS_DEPENDENCY(LiveStacks)
1414df029ccSDimitry Andric INITIALIZE_PASS_END(AMDGPUMarkLastScratchLoad, DEBUG_TYPE,
1424df029ccSDimitry Andric                     "AMDGPU Mark last scratch load", false, false)
143