1 //===-- AMDGPUMarkLastScratchLoad.cpp -------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Mark scratch load/spill instructions which are guaranteed to be the last time
10 // this scratch slot is used so it can be evicted from caches.
12 // TODO: Handle general stack accesses not just spilling.
14 //===----------------------------------------------------------------------===//
17 #include "GCNSubtarget.h"
18 #include "llvm/CodeGen/LiveIntervals.h"
19 #include "llvm/CodeGen/LiveStacks.h"
20 #include "llvm/CodeGen/MachineOperand.h"
24 #define DEBUG_TYPE "amdgpu-mark-last-scratch-load"
28 class AMDGPUMarkLastScratchLoad
: public MachineFunctionPass
{
30 LiveStacks
*LS
= nullptr;
31 LiveIntervals
*LIS
= nullptr;
32 SlotIndexes
*SI
= nullptr;
33 const SIInstrInfo
*SII
= nullptr;
38 AMDGPUMarkLastScratchLoad() : MachineFunctionPass(ID
) {
39 initializeAMDGPUMarkLastScratchLoadPass(*PassRegistry::getPassRegistry());
42 bool runOnMachineFunction(MachineFunction
&MF
) override
;
44 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
45 AU
.addRequired
<SlotIndexesWrapperPass
>();
46 AU
.addRequired
<LiveIntervalsWrapperPass
>();
47 AU
.addRequired
<LiveStacks
>();
49 MachineFunctionPass::getAnalysisUsage(AU
);
52 StringRef
getPassName() const override
{
53 return "AMDGPU Mark Last Scratch Load";
57 } // end anonymous namespace
59 bool AMDGPUMarkLastScratchLoad::runOnMachineFunction(MachineFunction
&MF
) {
60 if (skipFunction(MF
.getFunction()))
63 const GCNSubtarget
&ST
= MF
.getSubtarget
<GCNSubtarget
>();
64 if (ST
.getGeneration() < AMDGPUSubtarget::GFX12
)
67 LS
= &getAnalysis
<LiveStacks
>();
68 LIS
= &getAnalysis
<LiveIntervalsWrapperPass
>().getLIS();
69 SI
= &getAnalysis
<SlotIndexesWrapperPass
>().getSI();
70 SII
= ST
.getInstrInfo();
71 SlotIndexes
&Slots
= *LIS
->getSlotIndexes();
73 const unsigned NumSlots
= LS
->getNumIntervals();
75 LLVM_DEBUG(dbgs() << "No live slots, skipping\n");
79 LLVM_DEBUG(dbgs() << LS
->getNumIntervals() << " intervals\n");
83 for (auto &[SS
, LI
] : *LS
) {
84 for (const LiveRange::Segment
&Segment
: LI
.segments
) {
86 // Ignore segments that run to the end of basic block because in this case
87 // slot is still live at the end of it.
88 if (Segment
.end
.isBlock())
91 const int FrameIndex
= Register::stackSlot2Index(LI
.reg());
92 MachineInstr
*LastLoad
= nullptr;
94 MachineInstr
*MISegmentEnd
= SI
->getInstructionFromIndex(Segment
.end
);
96 // If there is no instruction at this slot because it was deleted take the
97 // instruction from the next slot.
99 SlotIndex NextSlot
= Slots
.getNextNonNullIndex(Segment
.end
);
100 MISegmentEnd
= SI
->getInstructionFromIndex(NextSlot
);
103 MachineInstr
*MISegmentStart
= SI
->getInstructionFromIndex(Segment
.start
);
104 MachineBasicBlock
*BB
= MISegmentEnd
->getParent();
106 // Start iteration backwards from segment end until the start of basic
107 // block or start of segment if it is in the same basic block.
108 auto End
= BB
->rend();
109 if (MISegmentStart
&& MISegmentStart
->getParent() == BB
)
110 End
= MISegmentStart
->getReverseIterator();
112 for (auto MI
= MISegmentEnd
->getReverseIterator(); MI
!= End
; ++MI
) {
115 if (SII
->isLoadFromStackSlot(*MI
, LoadFI
) && LoadFI
== FrameIndex
) {
121 if (LastLoad
&& !LastLoad
->memoperands_empty()) {
122 MachineMemOperand
*MMO
= *LastLoad
->memoperands_begin();
123 MMO
->setFlags(MOLastUse
);
125 LLVM_DEBUG(dbgs() << " Found last load: " << *LastLoad
);
133 char AMDGPUMarkLastScratchLoad::ID
= 0;
135 char &llvm::AMDGPUMarkLastScratchLoadID
= AMDGPUMarkLastScratchLoad::ID
;
137 INITIALIZE_PASS_BEGIN(AMDGPUMarkLastScratchLoad
, DEBUG_TYPE
,
138 "AMDGPU Mark last scratch load", false, false)
139 INITIALIZE_PASS_DEPENDENCY(SlotIndexesWrapperPass
)
140 INITIALIZE_PASS_DEPENDENCY(LiveStacks
)
141 INITIALIZE_PASS_END(AMDGPUMarkLastScratchLoad
, DEBUG_TYPE
,
142 "AMDGPU Mark last scratch load", false, false)