LLVM 24.0.0git
AMDGPURewriteAGPRCopyMFMA.cpp
Go to the documentation of this file.
1//===-- AMDGPURewriteAGPRCopyMFMA.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 \brief Try to replace MFMA instructions using VGPRs with MFMA
10/// instructions using AGPRs. We expect MFMAs to be selected using VGPRs, and
11/// only use AGPRs if it helps avoid spilling. In this case, the MFMA will have
12/// copies between AGPRs and VGPRs and the AGPR variant of an MFMA pseudo. This
13/// pass will attempt to delete the cross register bank copy and replace the
14/// MFMA opcode.
15///
16/// TODO:
17/// - Handle rewrites of phis. This must be more careful than normal about the
18/// reassignment. We do not want to introduce an AGPR-to-AGPR copy inside of a
19/// loop, so it depends on the exact assignment of the copy.
20///
21/// - Update LiveIntervals incrementally instead of recomputing from scratch
22///
23//===----------------------------------------------------------------------===//
24
25#include "AMDGPU.h"
26#include "GCNSubtarget.h"
28#include "SIRegisterInfo.h"
29#include "llvm/ADT/Statistic.h"
41
42using namespace llvm;
43
44#define DEBUG_TYPE "amdgpu-rewrite-agpr-copy-mfma"
45
46DEBUG_COUNTER(RewriteAGPRCopyMFMACounter, DEBUG_TYPE,
47 "Controls which MFMA chains are rewritten to AGPR form");
48
49namespace {
50
51STATISTIC(NumMFMAsRewrittenToAGPR,
52 "Number of MFMA instructions rewritten to use AGPR form");
53
54/// Map from spill slot frame index to list of instructions which reference it.
55using SpillReferenceMap = DenseMap<int, SmallVector<MachineInstr *, 4>>;
56
57class AMDGPURewriteAGPRCopyMFMAImpl {
59 const GCNSubtarget &ST;
60 const SIInstrInfo &TII;
61 const SIRegisterInfo &TRI;
63 VirtRegMap &VRM;
64 LiveRegMatrix &LRM;
65 LiveIntervals &LIS;
66 LiveStacks &LSS;
67 const RegisterClassInfo &RegClassInfo;
69
70 bool attemptReassignmentsToAGPR(SmallSetVector<Register, 4> &InterferingRegs,
71 MCPhysReg PrefPhysReg) const;
72
73public:
74 AMDGPURewriteAGPRCopyMFMAImpl(MachineFunction &MF, VirtRegMap &VRM,
76 LiveStacks &LSS,
77 const RegisterClassInfo &RegClassInfo,
79 : MF(MF), ST(MF.getSubtarget<GCNSubtarget>()), TII(*ST.getInstrInfo()),
80 TRI(*ST.getRegisterInfo()), MRI(MF.getRegInfo()), VRM(VRM), LRM(LRM),
81 LIS(LIS), LSS(LSS), RegClassInfo(RegClassInfo), MDT(MDT) {}
82
83 bool isRewriteCandidate(const MachineInstr &MI) const {
84 return TII.isMAI(MI) && AMDGPU::getAGPRFormOp(MI.getOpcode()) != -1;
85 }
86
87 /// Find AV_* registers assigned to AGPRs (or virtual registers which were
88 /// already required to be AGPR).
89 ///
90 /// \return the assigned physical register that \p VReg is assigned to if it
91 /// is an AGPR, otherwise MCRegister().
92 MCRegister getAssignedAGPR(Register VReg) const {
93 MCRegister PhysReg = VRM.getPhys(VReg);
94 if (!PhysReg)
95 return MCRegister();
96
97 // If this is an AV register, we have to check if the actual assignment is
98 // to an AGPR
99 const TargetRegisterClass *AssignedRC = TRI.getPhysRegBaseClass(PhysReg);
100 return TRI.isAGPRClass(AssignedRC) ? PhysReg : MCRegister();
101 }
102
103 bool tryReassigningMFMAChain(MachineInstr &MFMA, Register MFMAHintReg,
104 MCPhysReg PhysRegHint) const;
105
106 /// Compute the register class constraints based on the uses of \p Reg,
107 /// excluding MFMA uses from which can be rewritten to change the register
108 /// class constraint. MFMA scale operands need to be constraint checked.
109 /// This should be nearly identical to MachineRegisterInfo::recomputeRegClass.
110
111 /// \p RewriteCandidates will collect the set of MFMA instructions that need
112 /// to have the opcode mutated to perform the replacement.
113 ///
114 /// \p RewriteRegs will accumulate the set of register used by those MFMAs
115 /// that need to have the register classes adjusted.
116 bool recomputeRegClassExceptRewritable(
117 Register Reg, SmallVectorImpl<MachineInstr *> &RewriteCandidates,
118 SmallSetVector<Register, 4> &RewriteRegs) const;
119
120 bool tryFoldCopiesToAGPR(Register VReg, MCRegister AssignedAGPR) const;
121 bool tryFoldCopiesFromAGPR(Register VReg, MCRegister AssignedAGPR) const;
122
123 /// Replace spill instruction \p SpillMI which loads/stores from/to \p SpillFI
124 /// with a COPY to the replacement register value \p VReg.
125 void replaceSpillWithCopyToVReg(MachineInstr &SpillMI, int SpillFI,
126 Register VReg) const;
127
128 /// Create a map from frame index to use instructions for spills. If a use of
129 /// the frame index does not consist only of spill instructions, it will not
130 /// be included in the map.
131 void collectSpillIndexUses(ArrayRef<LiveInterval *> StackIntervals,
132 SpillReferenceMap &Map) const;
133
134 /// Return true if the reload \p LoadMI of the stack slot with live interval
135 /// \p SlotLI is jointly dominated by the slot's spill stores, i.e. every path
136 /// from the entry block to the load passes through a store to the slot before
137 /// the load. \p StoreFreeReachable is the set of blocks reachable from the
138 /// entry block without passing through any store block for the slot.
139 bool isLoadJointlyDominatedByStores(
140 const MachineInstr &LoadMI, const LiveInterval &SlotLI,
141 const SmallPtrSetImpl<MachineBasicBlock *> &StoreFreeReachable) const;
142
143 /// Attempt to unspill VGPRs by finding a free register and replacing the
144 /// spill instructions with copies.
145 void eliminateSpillsOfReassignedVGPRs() const;
146
147 bool run(MachineFunction &MF) const;
148};
149
150bool AMDGPURewriteAGPRCopyMFMAImpl::recomputeRegClassExceptRewritable(
151 Register StartReg, SmallVectorImpl<MachineInstr *> &RewriteCandidates,
152 SmallSetVector<Register, 4> &RewriteRegs) const {
153 SmallVector<Register, 8> Worklist = {StartReg};
154
155 // Recursively visit all transitive MFMA users
156 while (!Worklist.empty()) {
157 Register Reg = Worklist.pop_back_val();
158 const TargetRegisterClass *OldRC = MRI.getRegClass(Reg);
159
160 // Inflate to the equivalent AV_* class.
161 const TargetRegisterClass *NewRC = TRI.getLargestLegalSuperClass(OldRC, MF);
162 if (OldRC == NewRC)
163 return false;
164
165 // Accumulate constraints from all uses.
166 for (MachineOperand &MO : MRI.reg_nodbg_operands(Reg)) {
167 // Apply the effect of the given operand to NewRC.
168 MachineInstr *MI = MO.getParent();
169
170 // We can swap the classes of dst + src2 as a pair to AGPR, so ignore the
171 // effects of rewrite candidates. It just so happens that we can use
172 // either AGPR or VGPR in src0/src1. We still need to check constraint
173 // effects for scale variant, which does not allow AGPR.
174 if (isRewriteCandidate(*MI)) {
175 int AGPROp = AMDGPU::getAGPRFormOp(MI->getOpcode());
176 const MCInstrDesc &AGPRDesc = TII.get(AGPROp);
177 const TargetRegisterClass *NewRC =
178 TII.getRegClass(AGPRDesc, MO.getOperandNo());
179 if (!TRI.hasAGPRs(NewRC))
180 return false;
181
182 const MachineOperand *VDst =
183 TII.getNamedOperand(*MI, AMDGPU::OpName::vdst);
184 const MachineOperand *Src2 =
185 TII.getNamedOperand(*MI, AMDGPU::OpName::src2);
186 for (const MachineOperand *Op : {VDst, Src2}) {
187 if (!Op->isReg())
188 continue;
189
190 Register OtherReg = Op->getReg();
191 if (OtherReg.isPhysical())
192 return false;
193
194 if (OtherReg != Reg && RewriteRegs.insert(OtherReg))
195 Worklist.push_back(OtherReg);
196 }
197
198 if (!is_contained(RewriteCandidates, MI)) {
199 LLVM_DEBUG({
200 Register VDstPhysReg = VRM.getPhys(VDst->getReg());
201 dbgs() << "Attempting to replace VGPR MFMA with AGPR version:"
202 << " Dst=[" << printReg(VDst->getReg()) << " => "
203 << printReg(VDstPhysReg, &TRI);
204
205 if (Src2->isReg()) {
206 Register Src2PhysReg = VRM.getPhys(Src2->getReg());
207 dbgs() << "], Src2=[" << printReg(Src2->getReg(), &TRI) << " => "
208 << printReg(Src2PhysReg, &TRI);
209 }
210
211 dbgs() << "]: " << MI;
212 });
213
214 RewriteCandidates.push_back(MI);
215 }
216
217 continue;
218 }
219
220 unsigned OpNo = &MO - &MI->getOperand(0);
221 NewRC = MI->getRegClassConstraintEffect(OpNo, NewRC, &TII, &TRI);
222 if (!NewRC || NewRC == OldRC) {
223 LLVM_DEBUG(dbgs() << "User of " << printReg(Reg, &TRI)
224 << " cannot be reassigned to "
225 << (NewRC ? TRI.getRegClassName(NewRC) : "NULL")
226 << ": " << *MI);
227 return false;
228 }
229 }
230 }
231
232 return true;
233}
234
235bool AMDGPURewriteAGPRCopyMFMAImpl::tryReassigningMFMAChain(
236 MachineInstr &MFMA, Register MFMAHintReg, MCPhysReg PhysRegHint) const {
237 // src2 and dst have the same physical class constraint; try to preserve
238 // the original src2 subclass if one were to exist.
239 SmallVector<MachineInstr *, 4> RewriteCandidates = {&MFMA};
240 SmallSetVector<Register, 4> RewriteRegs;
241
242 // Make sure we reassign the MFMA we found the copy from first. We want
243 // to ensure dst ends up in the physreg we were originally copying to.
244 RewriteRegs.insert(MFMAHintReg);
245
246 // We've found av = COPY (MFMA) (or MFMA (v = COPY av)) and need to verify
247 // that we can trivially rewrite src2 to use the new AGPR. If we can't
248 // trivially replace it, we're going to induce as many copies as we would have
249 // emitted in the first place, as well as need to assign another register, and
250 // need to figure out where to put them. The live range splitting is smarter
251 // than anything we're doing here, so trust it did something reasonable.
252 //
253 // Note recomputeRegClassExceptRewritable will consider the constraints of
254 // this MFMA's src2 as well as the src2/dst of any transitive MFMA users.
255 if (!recomputeRegClassExceptRewritable(MFMAHintReg, RewriteCandidates,
256 RewriteRegs)) {
257 LLVM_DEBUG(dbgs() << "Could not recompute the regclass of dst reg "
258 << printReg(MFMAHintReg, &TRI) << '\n');
259 return false;
260 }
261
262 // If src2 and dst are different registers, we need to also reassign the
263 // input to an available AGPR if it is compatible with all other uses.
264 //
265 // If we can't reassign it, we'd need to introduce a different copy
266 // which is likely worse than the copy we'd be saving.
267 //
268 // It's likely that the MFMA is used in sequence with other MFMAs; if we
269 // cannot migrate the full use/def chain of MFMAs, we would need to
270 // introduce intermediate copies somewhere. So we only make the
271 // transform if all the interfering MFMAs can also be migrated. Collect
272 // the set of rewritable MFMAs and check if we can assign an AGPR at
273 // that point.
274 //
275 // If any of the MFMAs aren't reassignable, we give up and rollback to
276 // the original register assignments.
277
278 using RecoloringStack =
280 RecoloringStack TentativeReassignments;
281
282 for (Register RewriteReg : RewriteRegs) {
283 LiveInterval &LI = LIS.getInterval(RewriteReg);
284 TentativeReassignments.push_back({&LI, VRM.getPhys(RewriteReg)});
285 LRM.unassign(LI);
286 }
287
288 if (!DebugCounter::shouldExecute(RewriteAGPRCopyMFMACounter) ||
289 !attemptReassignmentsToAGPR(RewriteRegs, PhysRegHint)) {
290 // Roll back the register assignments to the original state.
291 for (auto [LI, OldAssign] : TentativeReassignments) {
292 if (VRM.hasPhys(LI->reg()))
293 LRM.unassign(*LI);
294 LRM.assign(*LI, OldAssign);
295 }
296
297 return false;
298 }
299
300 // Fixup the register classes of the virtual registers now that we've
301 // committed to the reassignments.
302 for (Register InterferingReg : RewriteRegs) {
303 const TargetRegisterClass *EquivalentAGPRRegClass =
304 TRI.getEquivalentAGPRClass(MRI.getRegClass(InterferingReg));
305 MRI.setRegClass(InterferingReg, EquivalentAGPRRegClass);
306 }
307
308 for (MachineInstr *RewriteCandidate : RewriteCandidates) {
309 int NewMFMAOp = AMDGPU::getAGPRFormOp(RewriteCandidate->getOpcode());
310 RewriteCandidate->setDesc(TII.get(NewMFMAOp));
311 ++NumMFMAsRewrittenToAGPR;
312 }
313
314 return true;
315}
316
317/// Attempt to reassign the registers in \p InterferingRegs to be AGPRs, with a
318/// preference to use \p PhysReg first. Returns false if the reassignments
319/// cannot be trivially performed.
320bool AMDGPURewriteAGPRCopyMFMAImpl::attemptReassignmentsToAGPR(
321 SmallSetVector<Register, 4> &InterferingRegs, MCPhysReg PrefPhysReg) const {
322 // FIXME: The ordering may matter here, but we're just taking uselistorder
323 // with the special case of ensuring to process the starting instruction
324 // first. We probably should extract the priority advisor out of greedy and
325 // use that ordering.
326 for (Register InterferingReg : InterferingRegs) {
327 LiveInterval &ReassignLI = LIS.getInterval(InterferingReg);
328 const TargetRegisterClass *EquivalentAGPRRegClass =
329 TRI.getEquivalentAGPRClass(MRI.getRegClass(InterferingReg));
330
331 MCPhysReg Assignable = AMDGPU::NoRegister;
332 if (EquivalentAGPRRegClass->contains(PrefPhysReg) &&
333 LRM.checkInterference(ReassignLI, PrefPhysReg) ==
335 // First try to assign to the AGPR we were already copying to. This
336 // should be the first assignment we attempt. We have to guard
337 // against the use being a subregister (which doesn't have an exact
338 // class match).
339
340 // TODO: If this does happen to be a subregister use, we should
341 // still try to assign to a subregister of the original copy result.
342 Assignable = PrefPhysReg;
343 } else {
344 ArrayRef<MCPhysReg> AllocOrder =
345 RegClassInfo.getOrder(EquivalentAGPRRegClass);
346 for (MCPhysReg Reg : AllocOrder) {
347 if (LRM.checkInterference(ReassignLI, Reg) == LiveRegMatrix::IK_Free) {
348 Assignable = Reg;
349 break;
350 }
351 }
352 }
353
354 if (!Assignable) {
355 LLVM_DEBUG(dbgs() << "Unable to reassign VGPR "
356 << printReg(InterferingReg, &TRI)
357 << " to a free AGPR\n");
358 return false;
359 }
360
361 LLVM_DEBUG(dbgs() << "Reassigning VGPR " << printReg(InterferingReg, &TRI)
362 << " to " << printReg(Assignable, &TRI) << '\n');
363 LRM.assign(ReassignLI, Assignable);
364 }
365
366 return true;
367}
368
369/// Identify copies that look like:
370/// %vdst:vgpr = V_MFMA_.. %src0:av, %src1:av, %src2:vgpr
371/// %agpr = COPY %vgpr
372///
373/// Then try to replace the transitive uses of %src2 and %vdst with the AGPR
374/// versions of the MFMA. This should cover the common case.
375bool AMDGPURewriteAGPRCopyMFMAImpl::tryFoldCopiesToAGPR(
376 Register VReg, MCRegister AssignedAGPR) const {
377 bool MadeChange = false;
378 for (MachineInstr &UseMI : MRI.def_instructions(VReg)) {
379 if (!UseMI.isCopy())
380 continue;
381
382 Register CopySrcReg = UseMI.getOperand(1).getReg();
383 if (!CopySrcReg.isVirtual())
384 continue;
385
386 // TODO: Handle loop phis copied to AGPR. e.g.
387 //
388 // loop:
389 // %phi:vgpr = COPY %mfma:vgpr
390 // %mfma:vgpr = V_MFMA_xxx_vgprcd_e64 %a, %b, %phi
391 // s_cbranch_vccnz loop
392 //
393 // endloop:
394 // %agpr = mfma
395 //
396 // We need to be sure that %phi is assigned to the same physical register as
397 // %mfma, or else we will just be moving copies into the loop.
398
399 for (MachineInstr &CopySrcDefMI : MRI.def_instructions(CopySrcReg)) {
400 if (isRewriteCandidate(CopySrcDefMI) &&
401 tryReassigningMFMAChain(
402 CopySrcDefMI, CopySrcDefMI.getOperand(0).getReg(), AssignedAGPR))
403 MadeChange = true;
404 }
405 }
406
407 return MadeChange;
408}
409
410/// Identify copies that look like:
411/// %src:vgpr = COPY %src:agpr
412/// %vdst:vgpr = V_MFMA_... %src0:av, %src1:av, %src:vgpr
413///
414/// Then try to replace the transitive uses of %src2 and %vdst with the AGPR
415/// versions of the MFMA. This should cover rarer cases, and will generally be
416/// redundant with tryFoldCopiesToAGPR.
417bool AMDGPURewriteAGPRCopyMFMAImpl::tryFoldCopiesFromAGPR(
418 Register VReg, MCRegister AssignedAGPR) const {
419 bool MadeChange = false;
420 for (MachineInstr &UseMI : MRI.use_instructions(VReg)) {
421 if (!UseMI.isCopy())
422 continue;
423
424 Register CopyDstReg = UseMI.getOperand(0).getReg();
425 if (!CopyDstReg.isVirtual())
426 continue;
427 for (MachineOperand &CopyUseMO : MRI.reg_nodbg_operands(CopyDstReg)) {
428 if (!CopyUseMO.readsReg())
429 continue;
430
431 MachineInstr &CopyUseMI = *CopyUseMO.getParent();
432 if (isRewriteCandidate(CopyUseMI)) {
433 if (tryReassigningMFMAChain(CopyUseMI, CopyDstReg,
434 VRM.getPhys(CopyDstReg)))
435 MadeChange = true;
436 }
437 }
438 }
439
440 return MadeChange;
441}
442
443void AMDGPURewriteAGPRCopyMFMAImpl::replaceSpillWithCopyToVReg(
444 MachineInstr &SpillMI, int SpillFI, Register VReg) const {
445 const DebugLoc &DL = SpillMI.getDebugLoc();
446 MachineBasicBlock &MBB = *SpillMI.getParent();
447 MachineInstr *NewCopy;
448 if (SpillMI.mayStore()) {
449 NewCopy = BuildMI(MBB, SpillMI, DL, TII.get(TargetOpcode::COPY), VReg)
450 .add(SpillMI.getOperand(0));
451 } else {
452 NewCopy = BuildMI(MBB, SpillMI, DL, TII.get(TargetOpcode::COPY))
453 .add(SpillMI.getOperand(0))
454 .addReg(VReg);
455 }
456
457 LIS.ReplaceMachineInstrInMaps(SpillMI, *NewCopy);
458 SpillMI.eraseFromParent();
459}
460
461void AMDGPURewriteAGPRCopyMFMAImpl::collectSpillIndexUses(
462 ArrayRef<LiveInterval *> StackIntervals, SpillReferenceMap &Map) const {
463
464 SmallSet<int, 4> NeededFrameIndexes;
465 for (const LiveInterval *LI : StackIntervals)
466 NeededFrameIndexes.insert(LI->reg().stackSlotIndex());
467
468 for (MachineBasicBlock &MBB : MF) {
469 for (MachineInstr &MI : MBB) {
470 for (MachineOperand &MO : MI.operands()) {
471 if (!MO.isFI() || !NeededFrameIndexes.count(MO.getIndex()))
472 continue;
473
474 if (TII.isVGPRSpill(MI)) {
475 SmallVector<MachineInstr *, 4> &References = Map[MO.getIndex()];
476 References.push_back(&MI);
477 break;
478 }
479
480 // Verify this was really a spill instruction, if it's not just ignore
481 // all uses.
482
483 // TODO: This should probably be verifier enforced.
484 NeededFrameIndexes.erase(MO.getIndex());
485 Map.erase(MO.getIndex());
486 }
487 }
488 }
489}
490
491bool AMDGPURewriteAGPRCopyMFMAImpl::isLoadJointlyDominatedByStores(
492 const MachineInstr &LoadMI, const LiveInterval &SlotLI,
493 const SmallPtrSetImpl<MachineBasicBlock *> &StoreFreeReachable) const {
494 const MachineBasicBlock *LoadMBB = LoadMI.getParent();
495 if (!MDT.isReachableFromEntry(LoadMBB))
496 return true;
497
498 // Check if every path passed through a store block.
499 if (!StoreFreeReachable.contains(LoadMBB))
500 return true;
501
502 // Otherwise, there exists a path to this block that has not seen any store
503 // yet. We must ensure that within this block there is a store to this slot
504 // before the load. Consult the slot's LiveStacks interval: a store to the
505 // slot before the load means the slot is not live into this block but is
506 // live at the load. If the load reads an undef value, the slot is not live
507 // at the load, failing the joint-dominance check.
508 SlotIndex LoadIdx = LIS.getInstructionIndex(LoadMI);
509 return SlotLI.liveAt(LoadIdx) && !LIS.isLiveInToMBB(SlotLI, LoadMBB);
510}
511
512void AMDGPURewriteAGPRCopyMFMAImpl::eliminateSpillsOfReassignedVGPRs() const {
513 unsigned NumSlots = LSS.getNumIntervals();
514 if (NumSlots == 0)
515 return;
516
517 MachineFrameInfo &MFI = MF.getFrameInfo();
518
519 SmallVector<LiveInterval *, 32> StackIntervals;
520 StackIntervals.reserve(NumSlots);
521
522 for (auto &[Slot, LI] : LSS) {
523 if (!MFI.isSpillSlotObjectIndex(Slot) || MFI.isDeadObjectIndex(Slot))
524 continue;
525
526 const TargetRegisterClass *RC = LSS.getIntervalRegClass(Slot);
527 if (TRI.hasVGPRs(RC))
528 StackIntervals.push_back(&LI);
529 }
530
531 sort(StackIntervals, [](const LiveInterval *A, const LiveInterval *B) {
532 // The ordering has to be strictly weak.
533 /// Sort heaviest intervals first to prioritize their unspilling
534 if (A->weight() != B->weight())
535 return A->weight() > B->weight();
536
537 if (A->getSize() != B->getSize())
538 return A->getSize() > B->getSize();
539
540 // Tie breaker by number to avoid need for stable sort
541 return A->reg().stackSlotIndex() < B->reg().stackSlotIndex();
542 });
543
544 // FIXME: The APIs for dealing with the LiveInterval of a frame index are
545 // cumbersome. LiveStacks owns its LiveIntervals which refer to stack
546 // slots. We cannot use the usual LiveRegMatrix::assign and unassign on these,
547 // and must create a substitute virtual register to do so. This makes
548 // incremental updating here difficult; we need to actually perform the IR
549 // mutation to get the new vreg references in place to compute the register
550 // LiveInterval to perform an assignment to track the new interference
551 // correctly, and we can't simply migrate the LiveInterval we already have.
552 //
553 // To avoid walking through the entire function for each index, pre-collect
554 // all the instructions slot referencess.
555
556 DenseMap<int, SmallVector<MachineInstr *, 4>> SpillSlotReferences;
557 collectSpillIndexUses(StackIntervals, SpillSlotReferences);
558
559 for (LiveInterval *LI : StackIntervals) {
560 int Slot = LI->reg().stackSlotIndex();
561 auto SpillReferences = SpillSlotReferences.find(Slot);
562 if (SpillReferences == SpillSlotReferences.end())
563 continue;
564
565 // For each spill reload, every path from entry to the reload must pass
566 // through at least one spill store to the same stack slot.
567 SmallPtrSet<MachineBasicBlock *, 4> StoreBlocks;
568 for (MachineInstr *MI : SpillReferences->second) {
569 if (MI->mayStore() && MDT.isReachableFromEntry(MI->getParent()))
570 StoreBlocks.insert(MI->getParent());
571 }
572
573 if (StoreBlocks.empty()) {
574 LLVM_DEBUG(dbgs() << "Skipping " << printReg(Slot, &TRI)
575 << ": no reachable stores\n");
576 continue;
577 }
578
579 // Compute blocks reachable from entry without passing through a store
580 // block.
581 MachineBasicBlock &EntryMBB = MF.front();
582 SmallPtrSet<MachineBasicBlock *, 16> StoreFreeReachable = {&EntryMBB};
583 SmallVector<MachineBasicBlock *, 16> Worklist = {&EntryMBB};
584
585 while (!Worklist.empty()) {
586 MachineBasicBlock *MBB = Worklist.pop_back_val();
587 if (StoreBlocks.contains(MBB))
588 continue;
589
590 for (MachineBasicBlock *Succ : MBB->successors()) {
591 if (StoreFreeReachable.insert(Succ).second)
592 Worklist.push_back(Succ);
593 }
594 }
595
596 // Every reachable reload must be jointly dominated by the slot's stores.
597 if (!llvm::all_of(SpillReferences->second, [&](const MachineInstr *MI) {
598 return !MI->mayLoad() ||
599 isLoadJointlyDominatedByStores(*MI, *LI, StoreFreeReachable);
600 })) {
602 dbgs() << "Skipping " << printReg(Slot, &TRI)
603 << ": some reachable load not jointly dominated by stores\n");
604 continue;
605 }
606
607 const TargetRegisterClass *RC = LSS.getIntervalRegClass(Slot);
608
609 LLVM_DEBUG(dbgs() << "Trying to eliminate " << printReg(Slot, &TRI)
610 << " by reassigning\n");
611
612 ArrayRef<MCPhysReg> AllocOrder = RegClassInfo.getOrder(RC);
613
614 for (MCPhysReg PhysReg : AllocOrder) {
615 if (LRM.checkInterference(*LI, PhysReg) != LiveRegMatrix::IK_Free)
616 continue;
617
618 LLVM_DEBUG(dbgs() << "Reassigning " << *LI << " to "
619 << printReg(PhysReg, &TRI) << '\n');
620
621 const TargetRegisterClass *RC = LSS.getIntervalRegClass(Slot);
622 Register NewVReg = MRI.createVirtualRegister(RC);
623
624 for (MachineInstr *SpillMI : SpillReferences->second)
625 replaceSpillWithCopyToVReg(*SpillMI, Slot, NewVReg);
626
627 // TODO: We should be able to transfer the information from the stack
628 // slot's LiveInterval without recomputing from scratch with the
629 // replacement vreg uses.
630 LiveInterval &NewLI = LIS.createAndComputeVirtRegInterval(NewVReg);
631 VRM.grow();
632
633 // A spill slot can be stored to multiple times, so the replacement
634 // vreg may have multiple disconnected live range components. Split
635 // them into separate vregs to maintain the single-component invariant.
637 LIS.splitSeparateComponents(NewLI, SplitLIs);
638
639 LLVM_DEBUG({
640 if (!SplitLIs.empty()) {
641 dbgs() << "Split unspilled interval into " << (SplitLIs.size() + 1)
642 << " components\n";
643 }
644 });
645
646 LRM.assign(NewLI, PhysReg);
647 for (LiveInterval *SplitLI : SplitLIs) {
648 VRM.grow();
649 LRM.assign(*SplitLI, PhysReg);
650 }
651
652 MFI.RemoveStackObject(Slot);
653 break;
654 }
655 }
656}
657
658bool AMDGPURewriteAGPRCopyMFMAImpl::run(MachineFunction &MF) const {
659 // This only applies on subtargets that have a configurable AGPR vs. VGPR
660 // allocation.
661 if (!ST.hasGFX90AInsts())
662 return false;
663
664 // Early exit if no AGPRs were assigned.
665 if (!LRM.isPhysRegUsed(AMDGPU::AGPR0)) {
666 LLVM_DEBUG(dbgs() << "skipping function that did not allocate AGPRs\n");
667 return false;
668 }
669
670 bool MadeChange = false;
671
672 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
673 Register VReg = Register::index2VirtReg(I);
674 MCRegister AssignedAGPR = getAssignedAGPR(VReg);
675 if (!AssignedAGPR)
676 continue;
677
678 if (tryFoldCopiesToAGPR(VReg, AssignedAGPR))
679 MadeChange = true;
680 if (tryFoldCopiesFromAGPR(VReg, AssignedAGPR))
681 MadeChange = true;
682 }
683
684 // If we've successfully rewritten some MFMAs, we've alleviated some VGPR
685 // pressure. See if we can eliminate some spills now that those registers are
686 // more available.
687 if (MadeChange)
688 eliminateSpillsOfReassignedVGPRs();
689
690 return MadeChange;
691}
692
693class AMDGPURewriteAGPRCopyMFMALegacy : public MachineFunctionPass {
694public:
695 static char ID;
696
697 AMDGPURewriteAGPRCopyMFMALegacy() : MachineFunctionPass(ID) {}
698
699 bool runOnMachineFunction(MachineFunction &MF) override;
700
701 StringRef getPassName() const override {
702 return "AMDGPU Rewrite AGPR-Copy-MFMA";
703 }
704
705 void getAnalysisUsage(AnalysisUsage &AU) const override {
706 AU.addRequired<LiveIntervalsWrapperPass>();
707 AU.addRequired<VirtRegMapWrapperLegacy>();
708 AU.addRequired<LiveRegMatrixWrapperLegacy>();
709 AU.addRequired<LiveStacksWrapperLegacy>();
710 AU.addRequired<MachineRegisterClassInfoWrapperPass>();
711 AU.addRequired<MachineDominatorTreeWrapperPass>();
712
713 AU.addPreserved<LiveIntervalsWrapperPass>();
714 AU.addPreserved<VirtRegMapWrapperLegacy>();
715 AU.addPreserved<LiveRegMatrixWrapperLegacy>();
716 AU.addPreserved<LiveStacksWrapperLegacy>();
717 AU.addPreserved<MachineRegisterClassInfoWrapperPass>();
718 AU.addPreserved<MachineDominatorTreeWrapperPass>();
719
720 AU.setPreservesAll();
722 }
723};
724
725} // End anonymous namespace.
726
727INITIALIZE_PASS_BEGIN(AMDGPURewriteAGPRCopyMFMALegacy, DEBUG_TYPE,
728 "AMDGPU Rewrite AGPR-Copy-MFMA", false, false)
735INITIALIZE_PASS_END(AMDGPURewriteAGPRCopyMFMALegacy, DEBUG_TYPE,
736 "AMDGPU Rewrite AGPR-Copy-MFMA", false, false)
737
738char AMDGPURewriteAGPRCopyMFMALegacy::ID = 0;
739
741 AMDGPURewriteAGPRCopyMFMALegacy::ID;
742
743bool AMDGPURewriteAGPRCopyMFMALegacy::runOnMachineFunction(
744 MachineFunction &MF) {
745 if (skipFunction(MF.getFunction()))
746 return false;
747
748 auto &VRM = getAnalysis<VirtRegMapWrapperLegacy>().getVRM();
749 auto &LRM = getAnalysis<LiveRegMatrixWrapperLegacy>().getLRM();
750 auto &LIS = getAnalysis<LiveIntervalsWrapperPass>().getLIS();
751 auto &LSS = getAnalysis<LiveStacksWrapperLegacy>().getLS();
752 auto &RCI = getAnalysis<MachineRegisterClassInfoWrapperPass>().getRCI();
753 auto &MDT = getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
754 AMDGPURewriteAGPRCopyMFMAImpl Impl(MF, VRM, LRM, LIS, LSS, RCI, MDT);
755 return Impl.run(MF);
756}
757
761 VirtRegMap &VRM = MFAM.getResult<VirtRegMapAnalysis>(MF);
764 LiveStacks &LSS = MFAM.getResult<LiveStacksAnalysis>(MF);
767
768 AMDGPURewriteAGPRCopyMFMAImpl Impl(MF, VRM, LRM, LIS, LSS, RCI, MDT);
769 if (!Impl.run(MF))
770 return PreservedAnalyses::all();
772 PA.preserveSet<CFGAnalyses>()
773 .preserve<LiveStacksAnalysis>()
774 .preserve<VirtRegMapAnalysis>()
775 .preserve<SlotIndexesAnalysis>()
776 .preserve<LiveIntervalsAnalysis>()
777 .preserve<LiveRegMatrixAnalysis>()
778 .preserve<MachineRegisterClassAnalysis>();
779 return PA;
780}
MachineInstrBuilder & UseMI
AMDGPU Rewrite AGPR Copy MFMA
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
AMD GCN specific subclass of TargetSubtarget.
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#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 for SIRegisterInfo.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:119
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.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
static bool shouldExecute(CounterInfo &Counter)
bool isReachableFromEntry(const NodeT *A) const
isReachableFromEntry - Return true if A is dominated by the entry block of the function containing it...
Register reg() const
SlotIndex getInstructionIndex(const MachineInstr &Instr) const
Returns the base index of the given instruction.
LiveInterval & getInterval(Register Reg)
LLVM_ABI void splitSeparateComponents(LiveInterval &LI, SmallVectorImpl< LiveInterval * > &SplitLIs)
Split separate components in LiveInterval LI into separate intervals.
bool isLiveInToMBB(const LiveRange &LR, const MachineBasicBlock *mbb) const
LiveInterval & createAndComputeVirtRegInterval(Register Reg)
SlotIndex ReplaceMachineInstrInMaps(MachineInstr &MI, MachineInstr &NewMI)
bool liveAt(SlotIndex index) const
LLVM_ABI bool isPhysRegUsed(MCRegister PhysReg) const
Returns true if the given PhysReg has any live intervals assigned.
LLVM_ABI void unassign(const LiveInterval &VirtReg, bool ClearAllReferencingSegments=false)
Unassign VirtReg from its PhysReg.
@ IK_Free
No interference, go ahead and assign.
LLVM_ABI void assign(const LiveInterval &VirtReg, MCRegister PhysReg)
Assign VirtReg to PhysReg.
LLVM_ABI InterferenceKind checkInterference(const LiveInterval &VirtReg, MCRegister PhysReg)
Check for interference before assigning VirtReg to PhysReg.
unsigned getNumIntervals() const
Definition LiveStacks.h:60
bool contains(MCRegister Reg) const
contains - Return true if the specified register is included in this register class.
iterator_range< succ_iterator > successors()
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...
bool isSpillSlotObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a spill slot.
void RemoveStackObject(int ObjectIdx)
Remove or mark dead a statically sized stack object.
bool isDeadObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a dead object.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineBasicBlock * getParent() const
bool mayStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly modify memory.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
iterator_range< def_instr_iterator > def_instructions(Register Reg) const
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
iterator_range< use_instr_iterator > use_instructions(Register Reg) const
iterator_range< reg_nodbg_iterator > reg_nodbg_operands(Register Reg) const
unsigned getNumVirtRegs() const
getNumVirtRegs - Return the number of virtual registers created.
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
ArrayRef< MCPhysReg > getOrder(const TargetRegisterClass *RC) const
getOrder - Returns the preferred allocation order for RC.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
int stackSlotIndex() const
Compute the frame index from a register value representing a stack slot.
Definition Register.h:93
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:157
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
A SetVector that performs no allocations if smaller than a certain size.
Definition SetVector.h:345
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
Definition SmallSet.h:176
bool erase(const T &V)
Definition SmallSet.h:200
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition SmallSet.h:184
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void reserve(size_type N)
void push_back(const T &Elt)
MCRegister getPhys(Register virtReg) const
returns the physical register mapped to the specified virtual register
Definition VirtRegMap.h:91
LLVM_ABI void grow()
bool hasPhys(Register virtReg) const
returns true if the specified virtual register is mapped to a physical register
Definition VirtRegMap.h:87
LLVM_READONLY int32_t getAGPRFormOp(uint32_t Opcode)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
Definition MCRegister.h:21
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
char & AMDGPURewriteAGPRCopyMFMALegacyID
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58