43#define DEBUG_TYPE "amdgpu-rewrite-agpr-copy-mfma"
46 "Controls which MFMA chains are rewritten to AGPR form");
51 "Number of MFMA instructions rewritten to use AGPR form");
56class AMDGPURewriteAGPRCopyMFMAImpl {
79 TRI(*ST.getRegisterInfo()), MRI(MF.getRegInfo()), VRM(VRM), LRM(LRM),
80 LIS(LIS), LSS(LSS), RegClassInfo(RegClassInfo), MDT(MDT) {}
82 bool isRewriteCandidate(
const MachineInstr &
MI)
const {
91 MCRegister getAssignedAGPR(
Register VReg)
const {
92 MCRegister PhysReg = VRM.getPhys(VReg);
99 return TRI.isAGPRClass(AssignedRC) ? PhysReg : MCRegister();
102 bool tryReassigningMFMAChain(MachineInstr &
MFMA,
Register MFMAHintReg,
115 bool recomputeRegClassExceptRewritable(
116 Register Reg, SmallVectorImpl<MachineInstr *> &RewriteCandidates,
117 SmallSetVector<Register, 4> &RewriteRegs)
const;
119 bool tryFoldCopiesToAGPR(
Register VReg, MCRegister AssignedAGPR)
const;
120 bool tryFoldCopiesFromAGPR(
Register VReg, MCRegister AssignedAGPR)
const;
124 void replaceSpillWithCopyToVReg(MachineInstr &SpillMI,
int SpillFI,
131 SpillReferenceMap &Map)
const;
138 bool isLoadJointlyDominatedByStores(
139 const MachineInstr &LoadMI,
const LiveInterval &SlotLI,
140 const SmallPtrSetImpl<MachineBasicBlock *> &StoreFreeReachable)
const;
144 void eliminateSpillsOfReassignedVGPRs()
const;
149bool AMDGPURewriteAGPRCopyMFMAImpl::recomputeRegClassExceptRewritable(
155 while (!Worklist.
empty()) {
167 MachineInstr *
MI = MO.getParent();
173 if (isRewriteCandidate(*
MI)) {
175 const MCInstrDesc &AGPRDesc =
TII.get(AGPROp);
177 TII.getRegClass(AGPRDesc, MO.getOperandNo());
178 if (!
TRI.hasAGPRs(NewRC))
181 const MachineOperand *VDst =
182 TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
183 const MachineOperand *Src2 =
184 TII.getNamedOperand(*
MI, AMDGPU::OpName::src2);
185 for (
const MachineOperand *
Op : {VDst, Src2}) {
193 if (OtherReg !=
Reg && RewriteRegs.
insert(OtherReg))
200 dbgs() <<
"Attempting to replace VGPR MFMA with AGPR version:"
219 unsigned OpNo = &MO - &
MI->getOperand(0);
220 NewRC =
MI->getRegClassConstraintEffect(OpNo, NewRC, &
TII, &
TRI);
221 if (!NewRC || NewRC == OldRC) {
223 <<
" cannot be reassigned to "
224 << (NewRC ?
TRI.getRegClassName(NewRC) :
"NULL")
234bool AMDGPURewriteAGPRCopyMFMAImpl::tryReassigningMFMAChain(
238 SmallVector<MachineInstr *, 4> RewriteCandidates = {&
MFMA};
239 SmallSetVector<Register, 4> RewriteRegs;
243 RewriteRegs.
insert(MFMAHintReg);
254 if (!recomputeRegClassExceptRewritable(MFMAHintReg, RewriteCandidates,
256 LLVM_DEBUG(
dbgs() <<
"Could not recompute the regclass of dst reg "
277 using RecoloringStack =
279 RecoloringStack TentativeReassignments;
281 for (
Register RewriteReg : RewriteRegs) {
283 TentativeReassignments.push_back({&LI, VRM.
getPhys(RewriteReg)});
288 !attemptReassignmentsToAGPR(RewriteRegs, PhysRegHint)) {
290 for (
auto [LI, OldAssign] : TentativeReassignments) {
293 LRM.
assign(*LI, OldAssign);
301 for (
Register InterferingReg : RewriteRegs) {
304 MRI.
setRegClass(InterferingReg, EquivalentAGPRRegClass);
307 for (MachineInstr *RewriteCandidate : RewriteCandidates) {
309 RewriteCandidate->setDesc(
TII.get(NewMFMAOp));
310 ++NumMFMAsRewrittenToAGPR;
319bool AMDGPURewriteAGPRCopyMFMAImpl::attemptReassignmentsToAGPR(
320 SmallSetVector<Register, 4> &InterferingRegs,
MCPhysReg PrefPhysReg)
const {
325 for (
Register InterferingReg : InterferingRegs) {
326 LiveInterval &ReassignLI = LIS.
getInterval(InterferingReg);
330 MCPhysReg Assignable = AMDGPU::NoRegister;
331 if (EquivalentAGPRRegClass->
contains(PrefPhysReg) &&
341 Assignable = PrefPhysReg;
344 RegClassInfo.
getOrder(EquivalentAGPRRegClass);
356 <<
" to a free AGPR\n");
362 LRM.
assign(ReassignLI, Assignable);
374bool AMDGPURewriteAGPRCopyMFMAImpl::tryFoldCopiesToAGPR(
375 Register VReg, MCRegister AssignedAGPR)
const {
376 bool MadeChange =
false;
399 if (isRewriteCandidate(CopySrcDefMI) &&
400 tryReassigningMFMAChain(
401 CopySrcDefMI, CopySrcDefMI.getOperand(0).getReg(), AssignedAGPR))
416bool AMDGPURewriteAGPRCopyMFMAImpl::tryFoldCopiesFromAGPR(
417 Register VReg, MCRegister AssignedAGPR)
const {
418 bool MadeChange =
false;
427 if (!CopyUseMO.readsReg())
430 MachineInstr &CopyUseMI = *CopyUseMO.getParent();
431 if (isRewriteCandidate(CopyUseMI)) {
432 if (tryReassigningMFMAChain(CopyUseMI, CopyDstReg,
442void AMDGPURewriteAGPRCopyMFMAImpl::replaceSpillWithCopyToVReg(
443 MachineInstr &SpillMI,
int SpillFI,
Register VReg)
const {
446 MachineInstr *NewCopy;
460void AMDGPURewriteAGPRCopyMFMAImpl::collectSpillIndexUses(
463 SmallSet<int, 4> NeededFrameIndexes;
464 for (
const LiveInterval *LI : StackIntervals)
467 for (MachineBasicBlock &
MBB : MF) {
468 for (MachineInstr &
MI :
MBB) {
469 for (MachineOperand &MO :
MI.operands()) {
470 if (!MO.isFI() || !NeededFrameIndexes.
count(MO.getIndex()))
473 if (
TII.isVGPRSpill(
MI)) {
474 SmallVector<MachineInstr *, 4> &References =
Map[MO.getIndex()];
483 NeededFrameIndexes.
erase(MO.getIndex());
484 Map.erase(MO.getIndex());
490bool AMDGPURewriteAGPRCopyMFMAImpl::isLoadJointlyDominatedByStores(
491 const MachineInstr &LoadMI,
const LiveInterval &SlotLI,
492 const SmallPtrSetImpl<MachineBasicBlock *> &StoreFreeReachable)
const {
493 const MachineBasicBlock *LoadMBB = LoadMI.
getParent();
498 if (!StoreFreeReachable.
contains(LoadMBB))
511void AMDGPURewriteAGPRCopyMFMAImpl::eliminateSpillsOfReassignedVGPRs()
const {
516 MachineFrameInfo &MFI = MF.getFrameInfo();
519 StackIntervals.
reserve(NumSlots);
521 for (
auto &[Slot, LI] : LSS) {
526 if (
TRI.hasVGPRs(RC))
530 sort(StackIntervals, [](
const LiveInterval *
A,
const LiveInterval *
B) {
533 if (
A->weight() !=
B->weight())
534 return A->weight() >
B->weight();
536 if (
A->getSize() !=
B->getSize())
537 return A->getSize() >
B->getSize();
540 return A->reg().stackSlotIndex() <
B->reg().stackSlotIndex();
555 DenseMap<int, SmallVector<MachineInstr *, 4>> SpillSlotReferences;
556 collectSpillIndexUses(StackIntervals, SpillSlotReferences);
558 for (LiveInterval *LI : StackIntervals) {
560 auto SpillReferences = SpillSlotReferences.find(Slot);
561 if (SpillReferences == SpillSlotReferences.end())
566 SmallPtrSet<MachineBasicBlock *, 4> StoreBlocks;
567 for (MachineInstr *
MI : SpillReferences->second) {
569 StoreBlocks.
insert(
MI->getParent());
572 if (StoreBlocks.
empty()) {
574 <<
": no reachable stores\n");
580 MachineBasicBlock &EntryMBB = MF.front();
581 SmallPtrSet<MachineBasicBlock *, 16> StoreFreeReachable = {&EntryMBB};
584 while (!Worklist.
empty()) {
590 if (StoreFreeReachable.
insert(Succ).second)
596 if (!
llvm::all_of(SpillReferences->second, [&](
const MachineInstr *
MI) {
597 return !MI->mayLoad() ||
598 isLoadJointlyDominatedByStores(*MI, *LI, StoreFreeReachable);
602 <<
": some reachable load not jointly dominated by stores\n");
609 <<
" by reassigning\n");
623 for (MachineInstr *SpillMI : SpillReferences->second)
624 replaceSpillWithCopyToVReg(*SpillMI, Slot, NewVReg);
639 if (!SplitLIs.
empty()) {
640 dbgs() <<
"Split unspilled interval into " << (SplitLIs.
size() + 1)
645 LRM.
assign(NewLI, PhysReg);
646 for (LiveInterval *SplitLI : SplitLIs) {
648 LRM.
assign(*SplitLI, PhysReg);
660 if (!
ST.hasGFX90AInsts())
665 LLVM_DEBUG(
dbgs() <<
"skipping function that did not allocate AGPRs\n");
669 bool MadeChange =
false;
672 Register VReg = Register::index2VirtReg(
I);
673 MCRegister AssignedAGPR = getAssignedAGPR(VReg);
677 if (tryFoldCopiesToAGPR(VReg, AssignedAGPR))
679 if (tryFoldCopiesFromAGPR(VReg, AssignedAGPR))
687 eliminateSpillsOfReassignedVGPRs();
692class AMDGPURewriteAGPRCopyMFMALegacy :
public MachineFunctionPass {
695 RegisterClassInfo RegClassInfo;
697 AMDGPURewriteAGPRCopyMFMALegacy() : MachineFunctionPass(
ID) {}
701 StringRef getPassName()
const override {
702 return "AMDGPU Rewrite AGPR-Copy-MFMA";
705 void getAnalysisUsage(AnalysisUsage &AU)
const override {
726 "AMDGPU Rewrite AGPR-Copy-MFMA",
false,
false)
735char AMDGPURewriteAGPRCopyMFMALegacy::ID = 0;
738 AMDGPURewriteAGPRCopyMFMALegacy::ID;
740bool AMDGPURewriteAGPRCopyMFMALegacy::runOnMachineFunction(
742 if (skipFunction(MF.getFunction()))
747 auto &VRM = getAnalysis<VirtRegMapWrapperLegacy>().getVRM();
748 auto &LRM = getAnalysis<LiveRegMatrixWrapperLegacy>().getLRM();
749 auto &LIS = getAnalysis<LiveIntervalsWrapperPass>().getLIS();
750 auto &LSS = getAnalysis<LiveStacksWrapperLegacy>().getLS();
751 auto &MDT = getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
752 AMDGPURewriteAGPRCopyMFMAImpl Impl(MF, VRM, LRM, LIS, LSS, RegClassInfo, MDT);
767 AMDGPURewriteAGPRCopyMFMAImpl Impl(MF, VRM, LRM, LIS, LSS, RegClassInfo, MDT);
772 .preserve<LiveStacksAnalysis>()
774 .preserve<SlotIndexesAnalysis>()
776 .preserve<LiveRegMatrixAnalysis>();
MachineInstrBuilder & UseMI
AMDGPU Rewrite AGPR Copy MFMA
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.
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
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)
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.
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...
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
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.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
LLVM_ABI void runOnMachineFunction(const MachineFunction &MF, bool Rev=false)
runOnFunction - Prepare to answer questions about MF.
ArrayRef< MCPhysReg > getOrder(const TargetRegisterClass *RC) const
getOrder - Returns the preferred allocation order for RC.
Wrapper class representing virtual and physical registers.
int stackSlotIndex() const
Compute the frame index from a register value representing a stack slot.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
bool insert(const value_type &X)
Insert a new element into the SetVector.
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.
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
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
bool hasPhys(Register virtReg) const
returns true if the specified virtual register is mapped to a physical register
LLVM_READONLY int32_t getAGPRFormOp(uint32_t Opcode)
DXILDebugInfoMap run(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.
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)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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...
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.
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