LLVM 24.0.0git
AMDGPUGlobalISelDivergenceLowering.cpp
Go to the documentation of this file.
1//===-- AMDGPUGlobalISelDivergenceLowering.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/// \file
10/// GlobalISel pass that selects divergent i1 phis as lane mask phis.
11/// Lane mask merging uses same algorithm as SDAG in SILowerI1Copies.
12/// Handles all cases of temporal divergence.
13/// For divergent non-phi i1 and uniform i1 uses outside of the cycle this pass
14/// currently depends on LCSSA to insert phis with one incoming.
15//
16//===----------------------------------------------------------------------===//
17
18#include "AMDGPU.h"
20#include "SILowerI1Copies.h"
27
28#define DEBUG_TYPE "amdgpu-global-isel-divergence-lowering"
29
30using namespace llvm;
31
32namespace {
33
34class AMDGPUGlobalISelDivergenceLoweringLegacy : public MachineFunctionPass {
35public:
36 static char ID;
37
38public:
39 AMDGPUGlobalISelDivergenceLoweringLegacy() : MachineFunctionPass(ID) {}
40
41 bool runOnMachineFunction(MachineFunction &MF) override;
42
43 StringRef getPassName() const override {
44 return "AMDGPU GlobalISel divergence lowering";
45 }
46
47 void getAnalysisUsage(AnalysisUsage &AU) const override {
48 AU.setPreservesCFG();
53 }
54};
55
56class DivergenceLoweringHelper : public AMDGPU::PhiLoweringHelper {
57public:
58 DivergenceLoweringHelper(MachineFunction &MF, MachineDominatorTree &DT,
61
62private:
63 MachineUniformityInfo *MUI = nullptr;
65 Register buildRegCopyToLaneMask(Register Reg);
66
67public:
68 void markAsLaneMask(Register DstReg) const override;
69 void getCandidatesForLowering(
70 SmallVectorImpl<MachineInstr *> &Vreg1Phis) const override;
71 void collectIncomingValuesFromPhi(
72 const MachineInstr *MI,
73 SmallVectorImpl<AMDGPU::Incoming> &Incomings) const override;
74 void replaceDstReg(Register NewReg, Register OldReg,
75 MachineBasicBlock *MBB) override;
76 void buildMergeLaneMasks(MachineBasicBlock &MBB,
78 Register DstReg, Register PrevReg,
79 Register CurReg) override;
80 void constrainAsLaneMask(AMDGPU::Incoming &In) override;
81
82 bool lowerTemporalDivergence();
83 bool lowerTemporalDivergenceI1();
84};
85
86DivergenceLoweringHelper::DivergenceLoweringHelper(
89 : PhiLoweringHelper(MF, DT, PDT), MUI(MUI), B(MF) {}
90
91// _(s1) -> SReg_32/64(s1)
92void DivergenceLoweringHelper::markAsLaneMask(Register DstReg) const {
93 assert(MRI->getType(DstReg) == LLT::scalar(1));
94
95 if (MRI->getRegClassOrNull(DstReg)) {
96 if (MRI->constrainRegClass(DstReg, ST->getBoolRC()))
97 return;
98 llvm_unreachable("Failed to constrain register class");
99 }
100
101 MRI->setRegClass(DstReg, ST->getBoolRC());
102}
103
104void DivergenceLoweringHelper::getCandidatesForLowering(
105 SmallVectorImpl<MachineInstr *> &Vreg1Phis) const {
106 LLT S1 = LLT::scalar(1);
107
108 // Add divergent i1 G_PHIs to the list. Only consider G_PHI instructions,
109 // not PHI instructions that may have been created by earlier lowering stages
110 // (e.g., lowerTemporalDivergenceI1).
111 for (MachineBasicBlock &MBB : MF) {
112 for (MachineInstr &MI : MBB.phis()) {
113 if (MI.getOpcode() != TargetOpcode::G_PHI)
114 continue;
115 Register Dst = MI.getOperand(0).getReg();
116 if (MRI->getType(Dst) == S1 && MUI->isDivergentAtDef(Dst))
117 Vreg1Phis.push_back(&MI);
118 }
119 }
120}
121
122void DivergenceLoweringHelper::collectIncomingValuesFromPhi(
123 const MachineInstr *MI,
124 SmallVectorImpl<AMDGPU::Incoming> &Incomings) const {
125 for (unsigned i = 1; i < MI->getNumOperands(); i += 2) {
126 Incomings.emplace_back(MI->getOperand(i).getReg(),
127 MI->getOperand(i + 1).getMBB(), Register());
128 }
129}
130
131void DivergenceLoweringHelper::replaceDstReg(Register NewReg, Register OldReg,
133 BuildMI(*MBB, MBB->getFirstNonPHI(), {}, TII->get(AMDGPU::COPY), OldReg)
134 .addReg(NewReg);
135}
136
137// Copy Reg to new lane mask register, insert a copy after instruction that
138// defines Reg while skipping phis if needed.
139Register DivergenceLoweringHelper::buildRegCopyToLaneMask(Register Reg) {
140 Register LaneMask = AMDGPU::createLaneMaskReg(MRI, LaneMaskRegAttrs);
141 MachineInstr *Instr = MRI->getVRegDef(Reg);
142 MachineBasicBlock *MBB = Instr->getParent();
143 B.setInsertPt(*MBB, MBB->SkipPHIsAndLabels(std::next(Instr->getIterator())));
144 B.buildCopy(LaneMask, Reg);
145 return LaneMask;
146}
147
148// bb.previous
149// %PrevReg = ...
150//
151// bb.current
152// %CurReg = ...
153//
154// %DstReg - not defined
155//
156// -> (wave32 example, new registers have sreg_32 reg class and S1 LLT)
157//
158// bb.previous
159// %PrevReg = ...
160// %PrevRegCopy:sreg_32(s1) = COPY %PrevReg
161//
162// bb.current
163// %CurReg = ...
164// %CurRegCopy:sreg_32(s1) = COPY %CurReg
165// ...
166// %PrevMaskedReg:sreg_32(s1) = ANDN2 %PrevRegCopy, ExecReg - active lanes 0
167// %CurMaskedReg:sreg_32(s1) = AND %ExecReg, CurRegCopy - inactive lanes to 0
168// %DstReg:sreg_32(s1) = OR %PrevMaskedReg, CurMaskedReg
169//
170// DstReg = for active lanes rewrite bit in PrevReg with bit from CurReg
171void DivergenceLoweringHelper::buildMergeLaneMasks(
173 Register DstReg, Register PrevReg, Register CurReg) {
174 // DstReg = (PrevReg & !EXEC) | (CurReg & EXEC)
175 // TODO: check if inputs are constants or results of a compare.
176
177 Register PrevRegCopy = buildRegCopyToLaneMask(PrevReg);
178 Register CurRegCopy = buildRegCopyToLaneMask(CurReg);
179 Register PrevMaskedReg = AMDGPU::createLaneMaskReg(MRI, LaneMaskRegAttrs);
180 Register CurMaskedReg = AMDGPU::createLaneMaskReg(MRI, LaneMaskRegAttrs);
181
182 B.setInsertPt(MBB, I);
183 B.buildInstr(LMC->AndN2Opc, {PrevMaskedReg}, {PrevRegCopy, LMC->ExecReg});
184 B.buildInstr(LMC->AndOpc, {CurMaskedReg}, {LMC->ExecReg, CurRegCopy});
185 B.buildInstr(LMC->OrOpc, {DstReg}, {PrevMaskedReg, CurMaskedReg});
186}
187
188// GlobalISel has to constrain S1 incoming taken as-is with lane mask register
189// class. Insert a copy of Incoming.Reg to new lane mask inside Incoming.Block,
190// Incoming.Reg becomes that new lane mask.
191void DivergenceLoweringHelper::constrainAsLaneMask(AMDGPU::Incoming &In) {
192 B.setInsertPt(*In.Block, In.Block->getFirstTerminator());
193
194 auto Copy = B.buildCopy(LLT::scalar(1), In.Reg);
195 MRI->setRegClass(Copy.getReg(0), ST->getBoolRC());
196 In.Reg = Copy.getReg(0);
197}
198
199void replaceUsesOfRegInInstWith(Register Reg, MachineInstr *Inst,
200 Register NewReg) {
201 for (MachineOperand &Op : Inst->operands()) {
202 if (Op.isReg() && Op.getReg() == Reg)
203 Op.setReg(NewReg);
204 }
205}
206
207bool DivergenceLoweringHelper::lowerTemporalDivergence() {
210
211 for (auto [Reg, UseInst, _] : MUI->getTemporalDivergenceList()) {
212 if (MRI->getType(Reg) == LLT::scalar(1) || MUI->isDivergentAtDef(Reg) ||
213 ILMA.isS32S64LaneMask(Reg))
214 continue;
215
216 Register CachedTDCopy = TDCache.lookup(Reg);
217 if (CachedTDCopy) {
218 replaceUsesOfRegInInstWith(Reg, UseInst, CachedTDCopy);
219 continue;
220 }
221
222 MachineInstr *Inst = MRI->getVRegDef(Reg);
224 B.setInsertPt(*MBB, MBB->SkipPHIsAndLabels(std::next(Inst->getIterator())));
225
226 Register VgprReg = MRI->createGenericVirtualRegister(MRI->getType(Reg));
227 B.buildInstr(AMDGPU::COPY, {VgprReg}, {Reg})
228 .addUse(LMC->ExecReg, RegState::Implicit);
229
230 replaceUsesOfRegInInstWith(Reg, UseInst, VgprReg);
231 TDCache[Reg] = VgprReg;
232 }
233 return false;
234}
235
236bool DivergenceLoweringHelper::lowerTemporalDivergenceI1() {
237 MachineRegisterInfo::VRegAttrs BoolS1 = {ST->getBoolRC(), LLT::scalar(1)};
238 initializeLaneMaskRegisterAttributes(BoolS1);
240
241 const auto &CInfo = MUI->getCycleInfo();
242
243 // In case of use outside muliple nested cycles or muliple uses we only need
244 // to merge lane mask across largest relevant cycle.
246 for (auto [Reg, UseInst, LRC] : MUI->getTemporalDivergenceList()) {
247 if (MRI->getType(Reg) != LLT::scalar(1))
248 continue;
249
250 auto [LRCCacheIter, RegNotCached] = LRCCache.try_emplace(Reg);
251 auto &CycleMergedMask = LRCCacheIter->getSecond();
252 CycleRef &CachedLRC = CycleMergedMask.first;
253 if (RegNotCached || CInfo.contains(LRC, CachedLRC)) {
254 CachedLRC = LRC;
255 }
256 }
257
258 for (auto &LRCCacheEntry : LRCCache) {
259 Register Reg = LRCCacheEntry.first;
260 auto &CycleMergedMask = LRCCacheEntry.getSecond();
261 CycleRef Cycle = CycleMergedMask.first;
262
263 Register MergedMask = MRI->createVirtualRegister(BoolS1);
264 SSAUpdater.Initialize(MergedMask);
265
266 MachineBasicBlock *MBB = MRI->getDefBlock(Reg);
267 SSAUpdater.AddAvailableValue(MBB, MergedMask);
268
269 for (auto Entry : CInfo.getEntries(Cycle)) {
270 for (MachineBasicBlock *Pred : Entry->predecessors()) {
271 if (!CInfo.contains(Cycle, Pred)) {
272 B.setInsertPt(*Pred, Pred->getFirstTerminator());
273 auto ImplDef = B.buildInstr(AMDGPU::IMPLICIT_DEF, {BoolS1}, {});
274 SSAUpdater.AddAvailableValue(Pred, ImplDef.getReg(0));
275 }
276 }
277 }
278
279 buildMergeLaneMasks(*MBB, MBB->getFirstTerminator(), {}, MergedMask,
281
282 CycleMergedMask.second = MergedMask;
283 }
284
285 for (auto [Reg, UseInst, Cycle] : MUI->getTemporalDivergenceList()) {
286 if (MRI->getType(Reg) != LLT::scalar(1))
287 continue;
288
289 replaceUsesOfRegInInstWith(Reg, UseInst, LRCCache.lookup(Reg).second);
290 }
291
292 return false;
293}
294
295static bool runDivergenceLowering(MachineFunction &MF, MachineDominatorTree &DT,
298 DivergenceLoweringHelper Helper(MF, DT, PDT, &MUI);
299
300 bool Changed = false;
301 // Temporal divergence lowering needs to inspect list of instructions used
302 // outside cycle with divergent exit provided by uniformity analysis. Uniform
303 // instructions from the list require lowering, no instruction is deleted.
304 // Thus it needs to be run before lowerPhis that deletes phis that require
305 // lowering and replaces them with new instructions.
306
307 // Non-i1 temporal divergence lowering.
308 Changed |= Helper.lowerTemporalDivergence();
309 // This covers both uniform and divergent i1s. Lane masks are in sgpr and need
310 // to be updated in each iteration.
311 Changed |= Helper.lowerTemporalDivergenceI1();
312 // Temporal divergence lowering of divergent i1 phi used outside of the cycle
313 // could also be handled by lowerPhis but we do it in lowerTempDivergenceI1
314 // since in some case lowerPhis does unnecessary lane mask merging.
315 Changed |= Helper.lowerPhis();
316 return Changed;
317}
318
319} // End anonymous namespace.
320
321INITIALIZE_PASS_BEGIN(AMDGPUGlobalISelDivergenceLoweringLegacy, DEBUG_TYPE,
322 "AMDGPU GlobalISel divergence lowering", false, false)
326INITIALIZE_PASS_END(AMDGPUGlobalISelDivergenceLoweringLegacy, DEBUG_TYPE,
327 "AMDGPU GlobalISel divergence lowering", false, false)
328
329char AMDGPUGlobalISelDivergenceLoweringLegacy::ID = 0;
330
332 AMDGPUGlobalISelDivergenceLoweringLegacy::ID;
333
335 return new AMDGPUGlobalISelDivergenceLoweringLegacy();
336}
337
338bool AMDGPUGlobalISelDivergenceLoweringLegacy::runOnMachineFunction(
339 MachineFunction &MF) {
341 getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
343 getAnalysis<MachinePostDominatorTreeWrapperPass>().getPostDomTree();
345 getAnalysis<MachineUniformityAnalysisPass>().getUniformityInfo();
346
347 return runDivergenceLowering(MF, DT, PDT, MUI);
348}
349
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
constexpr LLT S1
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define DEBUG_TYPE
const HexagonInstrInfo * TII
#define _
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
This file declares the MachineIRBuilder class.
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
Interface definition of the PhiLoweringHelper class that implements lane mask merging algorithm for d...
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()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:275
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
Opaque handle to a cycle within a GenericCycleInfo that wraps the cycle's preorder index.
A debug info location.
Definition DebugLoc.h:126
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
Definition DenseMap.h:250
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:299
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
bool isDivergentAtDef(ConstValueRefT V) const
Whether V is divergent at its definition.
const CycleInfoT & getCycleInfo() const
The cycle info this analysis was computed with.
iterator_range< TemporalDivergenceTuple * > getTemporalDivergenceList() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
iterator_range< pred_iterator > predecessors()
MachineInstrBundleIterator< MachineInstr > iterator
Analysis pass which computes a MachineDominatorTree.
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
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.
Helper class to build MachineInstr.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
Representation of each machine instruction.
const MachineBasicBlock * getParent() const
mop_range operands()
MachineOperand class - Representation of each machine instruction operand.
MachinePostDominatorTree - an analysis pass wrapper for DominatorTree used to compute the post-domina...
MachineSSAUpdater - This class updates SSA form for a set of virtual registers defined in multiple bl...
Legacy analysis pass which computes a MachineUniformityInfo.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
Wrapper class representing virtual and physical registers.
Definition Register.h:20
Helper class for SSA formation on a set of values defined in multiple blocks.
Definition SSAUpdater.h:39
LLVM_ABI void Initialize(Type *Ty, StringRef Name)
Reset this object to get ready for a new set of SSA updates with type 'Ty'.
LLVM_ABI Value * GetValueInMiddleOfBlock(BasicBlock *BB)
Construct SSA form, materializing a value that is live in the middle of the specified block.
LLVM_ABI void AddAvailableValue(BasicBlock *BB, Value *V)
Indicate that a rewritten value is available in the specified block with the specified value.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
self_iterator getIterator()
Definition ilist_node.h:123
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Register createLaneMaskReg(MachineRegisterInfo *MRI, MachineRegisterInfo::VRegAttrs LaneMaskRegAttrs)
This is an optimization pass for GlobalISel generic memory operations.
char & AMDGPUGlobalISelDivergenceLoweringLegacyID
GenericUniformityInfo< MachineSSAContext > MachineUniformityInfo
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
@ Implicit
Not emitted register (e.g. carry, or temporary result).
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
DWARFExpression::Operation Op
FunctionPass * createAMDGPUGlobalISelDivergenceLoweringPass()
Incoming for lane mask phi as machine instruction, incoming register Reg and incoming block Block are...
All attributes(register class or bank and low-level type) a virtual register can have.