LLVM 24.0.0git
AMDGPURegBankSelect.cpp
Go to the documentation of this file.
1//===-- AMDGPURegBankSelect.cpp -------------------------------------------===//
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/// Assign register banks to all register operands of G_ instructions using
10/// machine uniformity analysis.
11/// Sgpr - uniform values and some lane masks
12/// Vgpr - divergent, non S1, values
13/// Vcc - divergent S1 values(lane masks)
14/// However in some cases G_ instructions with this register bank assignment
15/// can't be inst-selected. This is solved in AMDGPURegBankLegalize.
16//===----------------------------------------------------------------------===//
17
18#include "AMDGPU.h"
20#include "GCNSubtarget.h"
28
29#define DEBUG_TYPE "amdgpu-reg-bank-select"
30
31using namespace llvm;
32using namespace AMDGPU;
33
34namespace {
35
36class AMDGPURegBankSelectLegacy : public MachineFunctionPass {
37public:
38 static char ID;
39
40 AMDGPURegBankSelectLegacy() : MachineFunctionPass(ID) {}
41
42 bool runOnMachineFunction(MachineFunction &MF) override;
43
44 StringRef getPassName() const override {
45 return "AMDGPU Register Bank Select";
46 }
47
48 void getAnalysisUsage(AnalysisUsage &AU) const override {
53 }
54
55 // This pass assigns register banks to all virtual registers, and we maintain
56 // this property in subsequent passes
57 MachineFunctionProperties getSetProperties() const override {
58 return MachineFunctionProperties().setRegBankSelected();
59 }
60};
61
62} // End anonymous namespace.
63
64INITIALIZE_PASS_BEGIN(AMDGPURegBankSelectLegacy, DEBUG_TYPE,
65 "AMDGPU Register Bank Select", false, false)
69INITIALIZE_PASS_END(AMDGPURegBankSelectLegacy, DEBUG_TYPE,
70 "AMDGPU Register Bank Select", false, false)
71
72char AMDGPURegBankSelectLegacy::ID = 0;
73
74char &llvm::AMDGPURegBankSelectLegacyID = AMDGPURegBankSelectLegacy::ID;
75
77 return new AMDGPURegBankSelectLegacy();
78}
79
84 const MachineUniformityInfo &MUI;
85 const SIRegisterInfo &TRI;
86 const RegisterBank *SgprRB;
87 const RegisterBank *VgprRB;
88 const RegisterBank *VccRB;
89
90public:
93 const MachineUniformityInfo &MUI,
94 const SIRegisterInfo &TRI, const RegisterBankInfo &RBI)
95 : B(B), MRI(*B.getMRI()), ILMA(ILMA), MUI(MUI), TRI(TRI),
96 SgprRB(&RBI.getRegBank(AMDGPU::SGPRRegBankID)),
97 VgprRB(&RBI.getRegBank(AMDGPU::VGPRRegBankID)),
98 VccRB(&RBI.getRegBank(AMDGPU::VCCRegBankID)) {}
99
100 // Temporal divergence copy: COPY to vgpr with implicit use of $exec inside of
101 // the cycle
102 // Note: uniformity analysis does not consider that registers with vgpr def
103 // are divergent (you can have uniform value in vgpr).
104 // - TODO: implicit use of $exec could be implemented as indicator that
105 // instruction is divergent
107 MachineInstr *MI = MRI.getVRegDef(Reg);
108 if (!MI->isCopy() || MI->getNumImplicitOperands() != 1)
109 return false;
110
111 return MI->implicit_operands().begin()->getReg() == TRI.getExec();
112 }
113
115 if (!isTemporalDivergenceCopy(Reg) &&
116 (MUI.isUniformAtDef(Reg) || ILMA.isS32S64LaneMask(Reg)))
117 return SgprRB;
118 if (MRI.getType(Reg) == LLT::scalar(1))
119 return VccRB;
120 return VgprRB;
121 }
122
123 // %rc:RegClass(s32) = G_ ...
124 // ...
125 // %a = G_ ..., %rc
126 // ->
127 // %rb:RegBank(s32) = G_ ...
128 // %rc:RegClass(s32) = COPY %rb
129 // ...
130 // %a = G_ ..., %rb
132 const RegisterBank *RB) {
133 // Register that already has Register class got it during pre-inst selection
134 // of another instruction. Maybe cross bank copy was required so we insert a
135 // copy that can be removed later. This simplifies post regbanklegalize
136 // combiner and avoids need to special case some patterns.
137 Register Reg = DefOP.getReg();
138 LLT Ty = MRI.getType(Reg);
139 Register NewReg = MRI.createVirtualRegister({RB, Ty});
140 DefOP.setReg(NewReg);
141
142 auto &MBB = *MI.getParent();
143 B.setInsertPt(MBB, MBB.SkipPHIsAndLabels(std::next(MI.getIterator())));
144 B.buildCopy(Reg, NewReg);
145
146 // The problem was discovered for uniform S1 that was used as both
147 // lane mask(vcc) and regular sgpr S1.
148 // - lane-mask(vcc) use was by si_if, this use is divergent and requires
149 // non-trivial sgpr-S1-to-vcc copy. But pre-inst-selection of si_if sets
150 // sreg_64_xexec(S1) on def of uniform S1 making it lane-mask.
151 // - the regular sgpr S1(uniform) instruction is now broken since
152 // it uses sreg_64_xexec(S1) which is divergent.
153
154 // Replace virtual registers with register class on generic instructions
155 // uses with virtual registers with register bank.
156 for (auto &UseMI : make_early_inc_range(MRI.use_instructions(Reg))) {
157 if (UseMI.isPreISelOpcode()) {
158 for (MachineOperand &Op : UseMI.operands()) {
159 if (Op.isReg() && Op.getReg() == Reg)
160 Op.setReg(NewReg);
161 }
162 }
163 }
164 }
165
166 // %a = G_ ..., %rc
167 // ->
168 // %rb:RegBank(s32) = COPY %rc
169 // %a = G_ ..., %rb
171 const RegisterBank *RB) {
172 Register Reg = UseOP.getReg();
173
174 LLT Ty = MRI.getType(Reg);
175 Register NewReg = MRI.createVirtualRegister({RB, Ty});
176 UseOP.setReg(NewReg);
177
178 if (MI.isPHI()) {
179 auto DefMI = MRI.getVRegDef(Reg)->getIterator();
180 MachineBasicBlock *DefMBB = DefMI->getParent();
181 B.setInsertPt(*DefMBB, DefMBB->SkipPHIsAndLabels(std::next(DefMI)));
182 } else {
183 B.setInstr(MI);
184 }
185
186 B.buildCopy(NewReg, Reg);
187 }
188};
189
191 if (!Op.isReg())
192 return {};
193
194 // Operands of COPY and G_SI_CALL can be physical registers.
195 Register Reg = Op.getReg();
196 if (!Reg.isVirtual())
197 return {};
198
199 return Reg;
200}
201
202static bool
204 function_ref<const MachineUniformityInfo *()> GetMUI) {
205 if (MF.getProperties().hasFailedISel())
206 return false;
207
208 GISelCSEInfo &CSEInfo = *GetCSEInfo();
209 const MachineUniformityInfo &MUI = *GetMUI();
210
211 // Setup the instruction builder with CSE.
212 GISelObserverWrapper Observer;
213 Observer.addObserver(&CSEInfo);
214
215 CSEMIRBuilder B(MF);
216 B.setCSEInfo(&CSEInfo);
217 B.setChangeObserver(Observer);
218
219 RAIIDelegateInstaller DelegateInstaller(MF, &Observer);
220 RAIIMFObserverInstaller MFObserverInstaller(MF, Observer);
221
223 MachineRegisterInfo &MRI = *B.getMRI();
224 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
225 RegBankSelectHelper RBSHelper(B, ILMA, MUI, *ST.getRegisterInfo(),
226 *ST.getRegBankInfo());
227 // Virtual registers at this point don't have register banks.
228 // Virtual registers in def and use operands of already inst-selected
229 // instruction have register class.
230
231 for (MachineBasicBlock &MBB : MF) {
232 for (MachineInstr &MI : MBB) {
233 // Vregs in def and use operands of COPY can have either register class
234 // or bank. If there is neither on vreg in def operand, assign bank.
235 if (MI.isCopy()) {
236 Register DefReg = getVReg(MI.getOperand(0));
237 if (!DefReg.isValid() || MRI.getRegClassOrNull(DefReg))
238 continue;
239
240 assert(!MRI.getRegBankOrNull(DefReg));
241 MRI.setRegBank(DefReg, *RBSHelper.getRegBankToAssign(DefReg));
242 continue;
243 }
244
245 if (!MI.isPreISelOpcode())
246 continue;
247
248 // Vregs in def and use operands of G_ instructions need to have register
249 // banks assigned. Before this loop possible case are
250 // - (1) vreg without register class or bank in def or use operand
251 // - (2) vreg with register class in def operand
252 // - (3) vreg, defined by G_ instruction, in use operand
253 // - (4) vreg, defined by pre-inst-selected instruction, in use operand
254
255 // First three cases are handled in loop through all def operands of G_
256 // instructions. For case (1) simply setRegBank. Cases (2) and (3) are
257 // handled by reAssignRegBankOnDef.
258 for (MachineOperand &DefOP : MI.defs()) {
259 Register DefReg = getVReg(DefOP);
260 if (!DefReg.isValid())
261 continue;
262
263 const RegisterBank *RB = RBSHelper.getRegBankToAssign(DefReg);
264 if (MRI.getRegClassOrNull(DefReg))
265 RBSHelper.reAssignRegBankOnDef(MI, DefOP, RB);
266 else {
267 assert(!MRI.getRegBankOrNull(DefReg));
268 MRI.setRegBank(DefReg, *RB);
269 }
270 }
271
272 // Register bank select doesn't modify pre-inst-selected instructions.
273 // For case (4) need to insert a copy, handled by constrainRegBankUse.
274 for (MachineOperand &UseOP : MI.uses()) {
275 Register UseReg = getVReg(UseOP);
276 if (!UseReg.isValid())
277 continue;
278
279 // Skip case (3).
280 if (!MRI.getRegClassOrNull(UseReg) ||
282 continue;
283
284 // Use with register class defined by pre-inst-selected instruction.
285 const RegisterBank *RB = RBSHelper.getRegBankToAssign(UseReg);
286 RBSHelper.constrainRegBankUse(MI, UseOP, RB);
287 }
288 }
289 }
290
291 return true;
292}
293
294bool AMDGPURegBankSelectLegacy::runOnMachineFunction(MachineFunction &MF) {
295 return runRegBankSelect(
296 MF,
297 [&]() {
298 GISelCSEAnalysisWrapper &Wrapper =
299 getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
300 return &Wrapper.get(getAnalysis<TargetPassConfig>().getCSEConfig());
301 },
302 [&]() {
303 return &getAnalysis<MachineUniformityAnalysisPass>()
304 .getUniformityInfo();
305 });
306}
307
308PreservedAnalyses
311 MFPropsModifier _(*this, MF);
312
313 if (!runRegBankSelect(
314 MF, [&]() { return MFAM.getResult<GISelCSEAnalysis>(MF).get(); },
315 [&]() { return &MFAM.getResult<MachineUniformityAnalysis>(MF); }))
316 return PreservedAnalyses::all();
317
319}
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
static bool runRegBankSelect(MachineFunction &MF, function_ref< GISelCSEInfo *()> GetCSEInfo, function_ref< const MachineUniformityInfo *()> GetMUI)
static Register getVReg(MachineOperand &Op)
MachineBasicBlock & MBB
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Provides analysis for continuously CSEing during GISel passes.
This file implements a version of MachineIRBuilder which CSEs insts within a MachineBasicBlock.
AMD GCN specific subclass of TargetSubtarget.
#define DEBUG_TYPE
static Register UseReg(const MachineOperand &MO)
#define _
IRTranslator LLVM IR MI
Register Reg
Machine IR instance of the generic uniformity analysis.
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
Target-Independent Code Generator Pass Configuration Options pass.
const RegisterBank * getRegBankToAssign(Register Reg)
void reAssignRegBankOnDef(MachineInstr &MI, MachineOperand &DefOP, const RegisterBank *RB)
RegBankSelectHelper(MachineIRBuilder &B, AMDGPU::IntrinsicLaneMaskAnalyzer &ILMA, const MachineUniformityInfo &MUI, const SIRegisterInfo &TRI, const RegisterBankInfo &RBI)
bool isTemporalDivergenceCopy(Register Reg)
void constrainRegBankUse(MachineInstr &MI, MachineOperand &UseOP, const RegisterBank *RB)
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
Defines a builder that does CSE of MachineInstructions using GISelCSEInfo.
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
The actual analysis pass wrapper.
Definition CSEInfo.h:244
The CSE Analysis object.
Definition CSEInfo.h:72
Simple wrapper observer that takes several observers, and calls each one for each event.
void addObserver(GISelChangeObserver *O)
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
An RAII based helper class to modify MachineFunctionProperties when running pass.
LLVM_ABI iterator SkipPHIsAndLabels(iterator I)
Return the first instruction in MBB after I that is not a PHI or a label.
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.
Properties which a MachineFunction may have at a given point in time.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const MachineFunctionProperties & getProperties() const
Get the function properties.
Helper class to build MachineInstr.
Representation of each machine instruction.
bool isPreISelOpcode(QueryType Type=IgnoreBundle) const
Return true if this is an instruction that should go through the usual legalization steps.
MachineOperand class - Representation of each machine instruction operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
const RegisterBank * getRegBankOrNull(Register Reg) const
Return the register bank of Reg, or null if Reg has not been assigned a register bank or has been ass...
LLVM_ABI void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
Legacy analysis pass which computes a MachineUniformityInfo.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
A simple RAII based Delegate installer.
A simple RAII based Observer installer.
Holds all the information related to register banks.
This class implements the register bank concept.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isValid() const
Definition Register.h:112
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Target-Independent Code Generator Pass Configuration Options.
An efficient, type-erasing, non-owning reference to a callable.
This is an optimization pass for GlobalISel generic memory operations.
GenericUniformityInfo< MachineSSAContext > MachineUniformityInfo
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
DWARFExpression::Operation Op
FunctionPass * createAMDGPURegBankSelectLegacyPass()
char & AMDGPURegBankSelectLegacyID