LLVM 17.0.0git
AMDGPUReleaseVGPRs.cpp
Go to the documentation of this file.
1//===- AMDGPUReleaseVGPRs.cpp - Automatically release vgprs on GFX11+ -----===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// Insert S_SENDMSG instructions to release vgprs on GFX11+.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AMDGPU.h"
15#include "AMDGPUSubtarget.h"
16#include "GCNSubtarget.h"
18#include "SIDefines.h"
22#include <optional>
23using namespace llvm;
24
25#define DEBUG_TYPE "release-vgprs"
26
27namespace {
28
29class AMDGPUReleaseVGPRs : public MachineFunctionPass {
30public:
31 static char ID;
32
33 AMDGPUReleaseVGPRs() : MachineFunctionPass(ID) {}
34
35 void getAnalysisUsage(AnalysisUsage &AU) const override {
36 AU.setPreservesAll();
38 }
39
40 // Track if the last instruction referencing a vgpr in a MBB is a VMEM
41 // store. Because this pass is late in the pipeline, it is expected that the
42 // last vgpr use will likely be one of vmem store, ds, exp.
43 // Loads and others vgpr operations would have been
44 // deleted by this point, except for complex control flow involving loops.
45 // This is why we are just testing the type of instructions rather
46 // than the operands.
47 class LastVGPRUseIsVMEMStore {
48 BitVector BlockVMEMStore;
49
50 static std::optional<bool>
51 lastVGPRUseIsStore(const MachineBasicBlock &MBB) {
52 for (auto &MI : reverse(MBB.instrs())) {
53 // If it's a VMEM store, a VGPR will be used, return true.
55 MI.mayStore())
56 return true;
57
58 // If it's referencing a VGPR but is not a VMEM store, return false.
62 return false;
63 }
64 // Wait until the values are propagated from the predecessors
65 return std::nullopt;
66 }
67
68 public:
69 LastVGPRUseIsVMEMStore(const MachineFunction &MF)
70 : BlockVMEMStore(MF.getNumBlockIDs()) {
71
73 SmallVector<const MachineBasicBlock *> EndWithVMEMStoreBlocks;
74
75 for (const auto &MBB : MF) {
76 auto LastUseIsStore = lastVGPRUseIsStore(MBB);
77 if (!LastUseIsStore.has_value())
78 continue;
79
80 if (*LastUseIsStore) {
81 EndWithVMEMStoreBlocks.push_back(&MBB);
82 } else {
83 Visited.insert(&MBB);
84 }
85 }
86
87 for (const auto *MBB : EndWithVMEMStoreBlocks) {
88 for (const auto *Succ : depth_first_ext(MBB, Visited)) {
89 BlockVMEMStore[Succ->getNumber()] = true;
90 }
91 }
92 }
93
94 // Return true if the last instruction referencing a vgpr in this MBB
95 // is a VMEM store, otherwise return false.
96 bool isLastVGPRUseVMEMStore(const MachineBasicBlock &MBB) const {
97 return BlockVMEMStore[MBB.getNumber()];
98 }
99 };
100
101 static bool
102 runOnMachineBasicBlock(MachineBasicBlock &MBB, const SIInstrInfo *SII,
103 const LastVGPRUseIsVMEMStore &BlockVMEMStore) {
104
105 bool Changed = false;
106
107 for (auto &MI : MBB.terminators()) {
108 // Look for S_ENDPGM instructions
109 if (MI.getOpcode() == AMDGPU::S_ENDPGM ||
110 MI.getOpcode() == AMDGPU::S_ENDPGM_SAVED) {
111 // If the last instruction using a VGPR in the block is a VMEM store,
112 // release VGPRs. The VGPRs release will be placed just before ending
113 // the program
114 if (BlockVMEMStore.isLastVGPRUseVMEMStore(MBB)) {
115 BuildMI(MBB, MI, DebugLoc(), SII->get(AMDGPU::S_SENDMSG))
117 Changed = true;
118 }
119 }
120 }
121
122 return Changed;
123 }
124
125 bool runOnMachineFunction(MachineFunction &MF) override {
126 Function &F = MF.getFunction();
127 if (skipFunction(F) || !AMDGPU::isEntryFunctionCC(F.getCallingConv()))
128 return false;
129
130 // This pass only runs on GFX11+
131 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
132 if (ST.getGeneration() < AMDGPUSubtarget::GFX11)
133 return false;
134
135 LLVM_DEBUG(dbgs() << "AMDGPUReleaseVGPRs running on " << MF.getName()
136 << "\n");
137
138 const SIInstrInfo *SII = ST.getInstrInfo();
139 LastVGPRUseIsVMEMStore BlockVMEMStore(MF);
140
141 bool Changed = false;
142 for (auto &MBB : MF) {
143 Changed |= runOnMachineBasicBlock(MBB, SII, BlockVMEMStore);
144 }
145
146 return Changed;
147 }
148};
149
150} // namespace
151
152char AMDGPUReleaseVGPRs::ID = 0;
153
154char &llvm::AMDGPUReleaseVGPRsID = AMDGPUReleaseVGPRs::ID;
155
156INITIALIZE_PASS(AMDGPUReleaseVGPRs, DEBUG_TYPE, "Release VGPRs", false, false)
MachineBasicBlock & MBB
Provides AMDGPU specific target descriptions.
#define DEBUG_TYPE
Base class for AMDGPU specific classes of TargetSubtarget.
#define LLVM_DEBUG(X)
Definition: Debug.h:101
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
AMD GCN specific subclass of TargetSubtarget.
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition: MD5.cpp:55
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
Represent the analysis usage information of a pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
A debug info location.
Definition: DebugLoc.h:33
bool skipFunction(const Function &F) const
Optional passes call this function to check whether the pass should be skipped.
Definition: Pass.cpp:174
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
iterator_range< iterator > terminators()
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Function & getFunction()
Return the LLVM function that this machine code represents.
unsigned getNumBlockIDs() const
getNumBlockIDs - Return the number of MBB ID's allocated.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
static bool isDS(const MachineInstr &MI)
Definition: SIInstrInfo.h:492
static bool isVMEM(const MachineInstr &MI)
Definition: SIInstrInfo.h:370
static bool isEXP(const MachineInstr &MI)
Definition: SIInstrInfo.h:555
static bool isFLAT(const MachineInstr &MI)
Definition: SIInstrInfo.h:518
static bool isVALU(const MachineInstr &MI)
Definition: SIInstrInfo.h:362
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
iterator_range< df_ext_iterator< T, SetTy > > depth_first_ext(const T &G, SetTy &S)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
char & AMDGPUReleaseVGPRsID
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:511
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
std::pair< iterator, bool > insert(NodeRef N)