16527b2a4SSebastian Neubauer //===-- GCNNSAReassign.cpp - Reassign registers in NSA instructions -------===//
2c29d4915SStanislav Mekhanoshin //
3c29d4915SStanislav Mekhanoshin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c29d4915SStanislav Mekhanoshin // See https://llvm.org/LICENSE.txt for license information.
5c29d4915SStanislav Mekhanoshin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c29d4915SStanislav Mekhanoshin //
7c29d4915SStanislav Mekhanoshin //===----------------------------------------------------------------------===//
8c29d4915SStanislav Mekhanoshin //
9c29d4915SStanislav Mekhanoshin /// \file
10c29d4915SStanislav Mekhanoshin /// \brief Try to reassign registers on GFX10+ from non-sequential to sequential
116527b2a4SSebastian Neubauer /// in NSA image instructions. Later SIShrinkInstructions pass will replace NSA
12c29d4915SStanislav Mekhanoshin /// with sequential versions where possible.
13c29d4915SStanislav Mekhanoshin ///
14c29d4915SStanislav Mekhanoshin //===----------------------------------------------------------------------===//
15c29d4915SStanislav Mekhanoshin 
16c29d4915SStanislav Mekhanoshin #include "AMDGPU.h"
17560d7e04Sdfukalov #include "GCNSubtarget.h"
18c29d4915SStanislav Mekhanoshin #include "SIMachineFunctionInfo.h"
19*c155a944SJay Foad #include "SIRegisterInfo.h"
20c29d4915SStanislav Mekhanoshin #include "llvm/ADT/Statistic.h"
21c29d4915SStanislav Mekhanoshin #include "llvm/CodeGen/LiveIntervals.h"
22c29d4915SStanislav Mekhanoshin #include "llvm/CodeGen/LiveRegMatrix.h"
23c29d4915SStanislav Mekhanoshin #include "llvm/CodeGen/MachineFunctionPass.h"
24989f1c72Sserge-sans-paille #include "llvm/CodeGen/VirtRegMap.h"
2505da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
26c29d4915SStanislav Mekhanoshin 
27c29d4915SStanislav Mekhanoshin using namespace llvm;
28c29d4915SStanislav Mekhanoshin 
29c29d4915SStanislav Mekhanoshin #define DEBUG_TYPE "amdgpu-nsa-reassign"
30c29d4915SStanislav Mekhanoshin 
31c29d4915SStanislav Mekhanoshin STATISTIC(NumNSAInstructions,
32c29d4915SStanislav Mekhanoshin           "Number of NSA instructions with non-sequential address found");
33c29d4915SStanislav Mekhanoshin STATISTIC(NumNSAConverted,
34c29d4915SStanislav Mekhanoshin           "Number of NSA instructions changed to sequential");
35c29d4915SStanislav Mekhanoshin 
36c29d4915SStanislav Mekhanoshin namespace {
37c29d4915SStanislav Mekhanoshin 
38c29d4915SStanislav Mekhanoshin class GCNNSAReassign : public MachineFunctionPass {
39c29d4915SStanislav Mekhanoshin public:
40c29d4915SStanislav Mekhanoshin   static char ID;
41c29d4915SStanislav Mekhanoshin 
GCNNSAReassign()42c29d4915SStanislav Mekhanoshin   GCNNSAReassign() : MachineFunctionPass(ID) {
43c29d4915SStanislav Mekhanoshin     initializeGCNNSAReassignPass(*PassRegistry::getPassRegistry());
44c29d4915SStanislav Mekhanoshin   }
45c29d4915SStanislav Mekhanoshin 
46c29d4915SStanislav Mekhanoshin   bool runOnMachineFunction(MachineFunction &MF) override;
47c29d4915SStanislav Mekhanoshin 
getPassName() const48c29d4915SStanislav Mekhanoshin   StringRef getPassName() const override { return "GCN NSA Reassign"; }
49c29d4915SStanislav Mekhanoshin 
getAnalysisUsage(AnalysisUsage & AU) const50c29d4915SStanislav Mekhanoshin   void getAnalysisUsage(AnalysisUsage &AU) const override {
51c29d4915SStanislav Mekhanoshin     AU.addRequired<LiveIntervals>();
52c29d4915SStanislav Mekhanoshin     AU.addRequired<VirtRegMap>();
53c29d4915SStanislav Mekhanoshin     AU.addRequired<LiveRegMatrix>();
54c29d4915SStanislav Mekhanoshin     AU.setPreservesAll();
55c29d4915SStanislav Mekhanoshin     MachineFunctionPass::getAnalysisUsage(AU);
56c29d4915SStanislav Mekhanoshin   }
57c29d4915SStanislav Mekhanoshin 
58c29d4915SStanislav Mekhanoshin private:
59c29d4915SStanislav Mekhanoshin   typedef enum {
60c29d4915SStanislav Mekhanoshin     NOT_NSA,        // Not an NSA instruction
61c29d4915SStanislav Mekhanoshin     FIXED,          // NSA which we cannot modify
62c29d4915SStanislav Mekhanoshin     NON_CONTIGUOUS, // NSA with non-sequential address which we can try
63c29d4915SStanislav Mekhanoshin                     // to optimize.
64c29d4915SStanislav Mekhanoshin     CONTIGUOUS      // NSA with all sequential address registers
65c29d4915SStanislav Mekhanoshin   } NSA_Status;
66c29d4915SStanislav Mekhanoshin 
67c29d4915SStanislav Mekhanoshin   const GCNSubtarget *ST;
68c29d4915SStanislav Mekhanoshin 
69c29d4915SStanislav Mekhanoshin   const MachineRegisterInfo *MRI;
70c29d4915SStanislav Mekhanoshin 
71c29d4915SStanislav Mekhanoshin   const SIRegisterInfo *TRI;
72c29d4915SStanislav Mekhanoshin 
73c29d4915SStanislav Mekhanoshin   VirtRegMap *VRM;
74c29d4915SStanislav Mekhanoshin 
75c29d4915SStanislav Mekhanoshin   LiveRegMatrix *LRM;
76c29d4915SStanislav Mekhanoshin 
77c29d4915SStanislav Mekhanoshin   LiveIntervals *LIS;
78c29d4915SStanislav Mekhanoshin 
79c29d4915SStanislav Mekhanoshin   unsigned MaxNumVGPRs;
80c29d4915SStanislav Mekhanoshin 
81c29d4915SStanislav Mekhanoshin   const MCPhysReg *CSRegs;
82c29d4915SStanislav Mekhanoshin 
83c29d4915SStanislav Mekhanoshin   NSA_Status CheckNSA(const MachineInstr &MI, bool Fast = false) const;
84c29d4915SStanislav Mekhanoshin 
85c29d4915SStanislav Mekhanoshin   bool tryAssignRegisters(SmallVectorImpl<LiveInterval *> &Intervals,
86c29d4915SStanislav Mekhanoshin                           unsigned StartReg) const;
87c29d4915SStanislav Mekhanoshin 
88c29d4915SStanislav Mekhanoshin   bool canAssign(unsigned StartReg, unsigned NumRegs) const;
89c29d4915SStanislav Mekhanoshin 
90c29d4915SStanislav Mekhanoshin   bool scavengeRegs(SmallVectorImpl<LiveInterval *> &Intervals) const;
91c29d4915SStanislav Mekhanoshin };
92c29d4915SStanislav Mekhanoshin 
93c29d4915SStanislav Mekhanoshin } // End anonymous namespace.
94c29d4915SStanislav Mekhanoshin 
95c29d4915SStanislav Mekhanoshin INITIALIZE_PASS_BEGIN(GCNNSAReassign, DEBUG_TYPE, "GCN NSA Reassign",
96c29d4915SStanislav Mekhanoshin                       false, false)
97c29d4915SStanislav Mekhanoshin INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
98c29d4915SStanislav Mekhanoshin INITIALIZE_PASS_DEPENDENCY(VirtRegMap)
99c29d4915SStanislav Mekhanoshin INITIALIZE_PASS_DEPENDENCY(LiveRegMatrix)
100c29d4915SStanislav Mekhanoshin INITIALIZE_PASS_END(GCNNSAReassign, DEBUG_TYPE, "GCN NSA Reassign",
101c29d4915SStanislav Mekhanoshin                     false, false)
102c29d4915SStanislav Mekhanoshin 
103c29d4915SStanislav Mekhanoshin 
104c29d4915SStanislav Mekhanoshin char GCNNSAReassign::ID = 0;
105c29d4915SStanislav Mekhanoshin 
106c29d4915SStanislav Mekhanoshin char &llvm::GCNNSAReassignID = GCNNSAReassign::ID;
107c29d4915SStanislav Mekhanoshin 
108c29d4915SStanislav Mekhanoshin bool
tryAssignRegisters(SmallVectorImpl<LiveInterval * > & Intervals,unsigned StartReg) const109c29d4915SStanislav Mekhanoshin GCNNSAReassign::tryAssignRegisters(SmallVectorImpl<LiveInterval *> &Intervals,
110c29d4915SStanislav Mekhanoshin                                    unsigned StartReg) const {
111c29d4915SStanislav Mekhanoshin   unsigned NumRegs = Intervals.size();
112c29d4915SStanislav Mekhanoshin 
113c29d4915SStanislav Mekhanoshin   for (unsigned N = 0; N < NumRegs; ++N)
1146e85c3d5SMircea Trofin     if (VRM->hasPhys(Intervals[N]->reg()))
115c29d4915SStanislav Mekhanoshin       LRM->unassign(*Intervals[N]);
116c29d4915SStanislav Mekhanoshin 
117c29d4915SStanislav Mekhanoshin   for (unsigned N = 0; N < NumRegs; ++N)
11843d34799SMircea Trofin     if (LRM->checkInterference(*Intervals[N], MCRegister::from(StartReg + N)))
119c29d4915SStanislav Mekhanoshin       return false;
120c29d4915SStanislav Mekhanoshin 
121c29d4915SStanislav Mekhanoshin   for (unsigned N = 0; N < NumRegs; ++N)
12243d34799SMircea Trofin     LRM->assign(*Intervals[N], MCRegister::from(StartReg + N));
123c29d4915SStanislav Mekhanoshin 
124c29d4915SStanislav Mekhanoshin   return true;
125c29d4915SStanislav Mekhanoshin }
126c29d4915SStanislav Mekhanoshin 
canAssign(unsigned StartReg,unsigned NumRegs) const127c29d4915SStanislav Mekhanoshin bool GCNNSAReassign::canAssign(unsigned StartReg, unsigned NumRegs) const {
128c29d4915SStanislav Mekhanoshin   for (unsigned N = 0; N < NumRegs; ++N) {
129c29d4915SStanislav Mekhanoshin     unsigned Reg = StartReg + N;
130c29d4915SStanislav Mekhanoshin     if (!MRI->isAllocatable(Reg))
131c29d4915SStanislav Mekhanoshin       return false;
132c29d4915SStanislav Mekhanoshin 
133c29d4915SStanislav Mekhanoshin     for (unsigned I = 0; CSRegs[I]; ++I)
134c29d4915SStanislav Mekhanoshin       if (TRI->isSubRegisterEq(Reg, CSRegs[I]) &&
135c29d4915SStanislav Mekhanoshin           !LRM->isPhysRegUsed(CSRegs[I]))
136c29d4915SStanislav Mekhanoshin       return false;
137c29d4915SStanislav Mekhanoshin   }
138c29d4915SStanislav Mekhanoshin 
139c29d4915SStanislav Mekhanoshin   return true;
140c29d4915SStanislav Mekhanoshin }
141c29d4915SStanislav Mekhanoshin 
142c29d4915SStanislav Mekhanoshin bool
scavengeRegs(SmallVectorImpl<LiveInterval * > & Intervals) const143c29d4915SStanislav Mekhanoshin GCNNSAReassign::scavengeRegs(SmallVectorImpl<LiveInterval *> &Intervals) const {
144c29d4915SStanislav Mekhanoshin   unsigned NumRegs = Intervals.size();
145c29d4915SStanislav Mekhanoshin 
146c29d4915SStanislav Mekhanoshin   if (NumRegs > MaxNumVGPRs)
147c29d4915SStanislav Mekhanoshin     return false;
148c29d4915SStanislav Mekhanoshin   unsigned MaxReg = MaxNumVGPRs - NumRegs + AMDGPU::VGPR0;
149c29d4915SStanislav Mekhanoshin 
150c29d4915SStanislav Mekhanoshin   for (unsigned Reg = AMDGPU::VGPR0; Reg <= MaxReg; ++Reg) {
151c29d4915SStanislav Mekhanoshin     if (!canAssign(Reg, NumRegs))
152c29d4915SStanislav Mekhanoshin       continue;
153c29d4915SStanislav Mekhanoshin 
154c29d4915SStanislav Mekhanoshin     if (tryAssignRegisters(Intervals, Reg))
155c29d4915SStanislav Mekhanoshin       return true;
156c29d4915SStanislav Mekhanoshin   }
157c29d4915SStanislav Mekhanoshin 
158c29d4915SStanislav Mekhanoshin   return false;
159c29d4915SStanislav Mekhanoshin }
160c29d4915SStanislav Mekhanoshin 
161c29d4915SStanislav Mekhanoshin GCNNSAReassign::NSA_Status
CheckNSA(const MachineInstr & MI,bool Fast) const162c29d4915SStanislav Mekhanoshin GCNNSAReassign::CheckNSA(const MachineInstr &MI, bool Fast) const {
163c29d4915SStanislav Mekhanoshin   const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(MI.getOpcode());
164*c155a944SJay Foad   if (!Info)
165c29d4915SStanislav Mekhanoshin     return NSA_Status::NOT_NSA;
166c29d4915SStanislav Mekhanoshin 
167*c155a944SJay Foad   switch (Info->MIMGEncoding) {
168*c155a944SJay Foad   case AMDGPU::MIMGEncGfx10NSA:
169*c155a944SJay Foad   case AMDGPU::MIMGEncGfx11NSA:
170*c155a944SJay Foad     break;
171*c155a944SJay Foad   default:
172*c155a944SJay Foad     return NSA_Status::NOT_NSA;
173*c155a944SJay Foad   }
174*c155a944SJay Foad 
175c29d4915SStanislav Mekhanoshin   int VAddr0Idx =
176c29d4915SStanislav Mekhanoshin     AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::vaddr0);
177c29d4915SStanislav Mekhanoshin 
178c29d4915SStanislav Mekhanoshin   unsigned VgprBase = 0;
179c29d4915SStanislav Mekhanoshin   bool NSA = false;
180*c155a944SJay Foad   for (unsigned I = 0; I < Info->VAddrOperands; ++I) {
181c29d4915SStanislav Mekhanoshin     const MachineOperand &Op = MI.getOperand(VAddr0Idx + I);
1820c476111SDaniel Sanders     Register Reg = Op.getReg();
18334978602SJay Foad     if (Reg.isPhysical() || !VRM->isAssignedReg(Reg))
184c29d4915SStanislav Mekhanoshin       return NSA_Status::FIXED;
185c29d4915SStanislav Mekhanoshin 
1860c476111SDaniel Sanders     Register PhysReg = VRM->getPhys(Reg);
187c29d4915SStanislav Mekhanoshin 
188c29d4915SStanislav Mekhanoshin     if (!Fast) {
189c29d4915SStanislav Mekhanoshin       if (!PhysReg)
190c29d4915SStanislav Mekhanoshin         return NSA_Status::FIXED;
191c29d4915SStanislav Mekhanoshin 
192*c155a944SJay Foad       // TODO: address the below limitation to handle GFX11 BVH instructions
193c29d4915SStanislav Mekhanoshin       // Bail if address is not a VGPR32. That should be possible to extend the
194c29d4915SStanislav Mekhanoshin       // optimization to work with subregs of a wider register tuples, but the
195c29d4915SStanislav Mekhanoshin       // logic to find free registers will be much more complicated with much
196c29d4915SStanislav Mekhanoshin       // less chances for success. That seems reasonable to assume that in most
197c29d4915SStanislav Mekhanoshin       // cases a tuple is used because a vector variable contains different
1985464fd36SJoe Nash       // parts of an address and it is either already consecutive or cannot
199c29d4915SStanislav Mekhanoshin       // be reassigned if not. If needed it is better to rely on register
200c29d4915SStanislav Mekhanoshin       // coalescer to process such address tuples.
201*c155a944SJay Foad       if (TRI->getRegSizeInBits(*MRI->getRegClass(Reg)) != 32 || Op.getSubReg())
202c29d4915SStanislav Mekhanoshin         return NSA_Status::FIXED;
203c29d4915SStanislav Mekhanoshin 
204d91ee2f7SStanislav Mekhanoshin       // InlineSpiller does not call LRM::assign() after an LI split leaving
205d91ee2f7SStanislav Mekhanoshin       // it in an inconsistent state, so we cannot call LRM::unassign().
206d91ee2f7SStanislav Mekhanoshin       // See llvm bug #48911.
207d91ee2f7SStanislav Mekhanoshin       // Skip reassign if a register has originated from such split.
208d91ee2f7SStanislav Mekhanoshin       // FIXME: Remove the workaround when bug #48911 is fixed.
209d91ee2f7SStanislav Mekhanoshin       if (VRM->getPreSplitReg(Reg))
210d91ee2f7SStanislav Mekhanoshin         return NSA_Status::FIXED;
211d91ee2f7SStanislav Mekhanoshin 
212c29d4915SStanislav Mekhanoshin       const MachineInstr *Def = MRI->getUniqueVRegDef(Reg);
213c29d4915SStanislav Mekhanoshin 
214c29d4915SStanislav Mekhanoshin       if (Def && Def->isCopy() && Def->getOperand(1).getReg() == PhysReg)
215c29d4915SStanislav Mekhanoshin         return NSA_Status::FIXED;
216c29d4915SStanislav Mekhanoshin 
217c29d4915SStanislav Mekhanoshin       for (auto U : MRI->use_nodbg_operands(Reg)) {
218c29d4915SStanislav Mekhanoshin         if (U.isImplicit())
219c29d4915SStanislav Mekhanoshin           return NSA_Status::FIXED;
220c29d4915SStanislav Mekhanoshin         const MachineInstr *UseInst = U.getParent();
221c29d4915SStanislav Mekhanoshin         if (UseInst->isCopy() && UseInst->getOperand(0).getReg() == PhysReg)
222c29d4915SStanislav Mekhanoshin           return NSA_Status::FIXED;
223c29d4915SStanislav Mekhanoshin       }
224c29d4915SStanislav Mekhanoshin 
225c29d4915SStanislav Mekhanoshin       if (!LIS->hasInterval(Reg))
226c29d4915SStanislav Mekhanoshin         return NSA_Status::FIXED;
227c29d4915SStanislav Mekhanoshin     }
228c29d4915SStanislav Mekhanoshin 
229c29d4915SStanislav Mekhanoshin     if (I == 0)
230c29d4915SStanislav Mekhanoshin       VgprBase = PhysReg;
231c29d4915SStanislav Mekhanoshin     else if (VgprBase + I != PhysReg)
232c29d4915SStanislav Mekhanoshin       NSA = true;
233c29d4915SStanislav Mekhanoshin   }
234c29d4915SStanislav Mekhanoshin 
235c29d4915SStanislav Mekhanoshin   return NSA ? NSA_Status::NON_CONTIGUOUS : NSA_Status::CONTIGUOUS;
236c29d4915SStanislav Mekhanoshin }
237c29d4915SStanislav Mekhanoshin 
runOnMachineFunction(MachineFunction & MF)238c29d4915SStanislav Mekhanoshin bool GCNNSAReassign::runOnMachineFunction(MachineFunction &MF) {
239c29d4915SStanislav Mekhanoshin   ST = &MF.getSubtarget<GCNSubtarget>();
240c29d4915SStanislav Mekhanoshin   if (ST->getGeneration() < GCNSubtarget::GFX10)
241c29d4915SStanislav Mekhanoshin     return false;
242c29d4915SStanislav Mekhanoshin 
243c29d4915SStanislav Mekhanoshin   MRI = &MF.getRegInfo();
244c29d4915SStanislav Mekhanoshin   TRI = ST->getRegisterInfo();
245c29d4915SStanislav Mekhanoshin   VRM = &getAnalysis<VirtRegMap>();
246c29d4915SStanislav Mekhanoshin   LRM = &getAnalysis<LiveRegMatrix>();
247c29d4915SStanislav Mekhanoshin   LIS = &getAnalysis<LiveIntervals>();
248c29d4915SStanislav Mekhanoshin 
249c29d4915SStanislav Mekhanoshin   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
250c29d4915SStanislav Mekhanoshin   MaxNumVGPRs = ST->getMaxNumVGPRs(MF);
251c29d4915SStanislav Mekhanoshin   MaxNumVGPRs = std::min(ST->getMaxNumVGPRs(MFI->getOccupancy()), MaxNumVGPRs);
252e0b84434SMatt Arsenault   CSRegs = MRI->getCalleeSavedRegs();
253c29d4915SStanislav Mekhanoshin 
254c29d4915SStanislav Mekhanoshin   using Candidate = std::pair<const MachineInstr*, bool>;
255c29d4915SStanislav Mekhanoshin   SmallVector<Candidate, 32> Candidates;
256c29d4915SStanislav Mekhanoshin   for (const MachineBasicBlock &MBB : MF) {
257c29d4915SStanislav Mekhanoshin     for (const MachineInstr &MI : MBB) {
258c29d4915SStanislav Mekhanoshin       switch (CheckNSA(MI)) {
259c29d4915SStanislav Mekhanoshin       default:
260c29d4915SStanislav Mekhanoshin         continue;
261c29d4915SStanislav Mekhanoshin       case NSA_Status::CONTIGUOUS:
262c29d4915SStanislav Mekhanoshin         Candidates.push_back(std::make_pair(&MI, true));
263c29d4915SStanislav Mekhanoshin         break;
264c29d4915SStanislav Mekhanoshin       case NSA_Status::NON_CONTIGUOUS:
265c29d4915SStanislav Mekhanoshin         Candidates.push_back(std::make_pair(&MI, false));
266c29d4915SStanislav Mekhanoshin         ++NumNSAInstructions;
267c29d4915SStanislav Mekhanoshin         break;
268c29d4915SStanislav Mekhanoshin       }
269c29d4915SStanislav Mekhanoshin     }
270c29d4915SStanislav Mekhanoshin   }
271c29d4915SStanislav Mekhanoshin 
272c29d4915SStanislav Mekhanoshin   bool Changed = false;
273c29d4915SStanislav Mekhanoshin   for (auto &C : Candidates) {
274c29d4915SStanislav Mekhanoshin     if (C.second)
275c29d4915SStanislav Mekhanoshin       continue;
276c29d4915SStanislav Mekhanoshin 
277c29d4915SStanislav Mekhanoshin     const MachineInstr *MI = C.first;
278c29d4915SStanislav Mekhanoshin     if (CheckNSA(*MI, true) == NSA_Status::CONTIGUOUS) {
279c29d4915SStanislav Mekhanoshin       // Already happen to be fixed.
280c29d4915SStanislav Mekhanoshin       C.second = true;
281c29d4915SStanislav Mekhanoshin       ++NumNSAConverted;
282c29d4915SStanislav Mekhanoshin       continue;
283c29d4915SStanislav Mekhanoshin     }
284c29d4915SStanislav Mekhanoshin 
285c29d4915SStanislav Mekhanoshin     const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(MI->getOpcode());
286c29d4915SStanislav Mekhanoshin     int VAddr0Idx =
287c29d4915SStanislav Mekhanoshin       AMDGPU::getNamedOperandIdx(MI->getOpcode(), AMDGPU::OpName::vaddr0);
288c29d4915SStanislav Mekhanoshin 
289c29d4915SStanislav Mekhanoshin     SmallVector<LiveInterval *, 16> Intervals;
29043d34799SMircea Trofin     SmallVector<MCRegister, 16> OrigRegs;
291c29d4915SStanislav Mekhanoshin     SlotIndex MinInd, MaxInd;
292*c155a944SJay Foad     for (unsigned I = 0; I < Info->VAddrOperands; ++I) {
293c29d4915SStanislav Mekhanoshin       const MachineOperand &Op = MI->getOperand(VAddr0Idx + I);
2940c476111SDaniel Sanders       Register Reg = Op.getReg();
295c29d4915SStanislav Mekhanoshin       LiveInterval *LI = &LIS->getInterval(Reg);
2962dc4a14eSKazu Hirata       if (llvm::is_contained(Intervals, LI)) {
297c29d4915SStanislav Mekhanoshin         // Same register used, unable to make sequential
298c29d4915SStanislav Mekhanoshin         Intervals.clear();
299c29d4915SStanislav Mekhanoshin         break;
300c29d4915SStanislav Mekhanoshin       }
301c29d4915SStanislav Mekhanoshin       Intervals.push_back(LI);
302c29d4915SStanislav Mekhanoshin       OrigRegs.push_back(VRM->getPhys(Reg));
303ba811016SNicolai Hähnle       if (LI->empty()) {
304ba811016SNicolai Hähnle         // The address input is undef, so it doesn't contribute to the relevant
305ba811016SNicolai Hähnle         // range. Seed a reasonable index range if required.
306ba811016SNicolai Hähnle         if (I == 0)
307ba811016SNicolai Hähnle           MinInd = MaxInd = LIS->getInstructionIndex(*MI);
308ba811016SNicolai Hähnle         continue;
309ba811016SNicolai Hähnle       }
310ba811016SNicolai Hähnle       MinInd = I != 0 ? std::min(MinInd, LI->beginIndex()) : LI->beginIndex();
311ba811016SNicolai Hähnle       MaxInd = I != 0 ? std::max(MaxInd, LI->endIndex()) : LI->endIndex();
312c29d4915SStanislav Mekhanoshin     }
313c29d4915SStanislav Mekhanoshin 
314c29d4915SStanislav Mekhanoshin     if (Intervals.empty())
315c29d4915SStanislav Mekhanoshin       continue;
316c29d4915SStanislav Mekhanoshin 
317c29d4915SStanislav Mekhanoshin     LLVM_DEBUG(dbgs() << "Attempting to reassign NSA: " << *MI
318c29d4915SStanislav Mekhanoshin                       << "\tOriginal allocation:\t";
3196e85c3d5SMircea Trofin                for (auto *LI
3206e85c3d5SMircea Trofin                     : Intervals) dbgs()
3216e85c3d5SMircea Trofin                << " " << llvm::printReg((VRM->getPhys(LI->reg())), TRI);
322c29d4915SStanislav Mekhanoshin                dbgs() << '\n');
323c29d4915SStanislav Mekhanoshin 
324c29d4915SStanislav Mekhanoshin     bool Success = scavengeRegs(Intervals);
325c29d4915SStanislav Mekhanoshin     if (!Success) {
326c29d4915SStanislav Mekhanoshin       LLVM_DEBUG(dbgs() << "\tCannot reallocate.\n");
3276e85c3d5SMircea Trofin       if (VRM->hasPhys(Intervals.back()->reg())) // Did not change allocation.
328c29d4915SStanislav Mekhanoshin         continue;
329c29d4915SStanislav Mekhanoshin     } else {
330c29d4915SStanislav Mekhanoshin       // Check we did not make it worse for other instructions.
331c29d4915SStanislav Mekhanoshin       auto I = std::lower_bound(Candidates.begin(), &C, MinInd,
332c29d4915SStanislav Mekhanoshin                                 [this](const Candidate &C, SlotIndex I) {
333c29d4915SStanislav Mekhanoshin                                   return LIS->getInstructionIndex(*C.first) < I;
334c29d4915SStanislav Mekhanoshin                                 });
335c29d4915SStanislav Mekhanoshin       for (auto E = Candidates.end(); Success && I != E &&
336c29d4915SStanislav Mekhanoshin               LIS->getInstructionIndex(*I->first) < MaxInd; ++I) {
337c29d4915SStanislav Mekhanoshin         if (I->second && CheckNSA(*I->first, true) < NSA_Status::CONTIGUOUS) {
338c29d4915SStanislav Mekhanoshin           Success = false;
339c29d4915SStanislav Mekhanoshin           LLVM_DEBUG(dbgs() << "\tNSA conversion conflict with " << *I->first);
340c29d4915SStanislav Mekhanoshin         }
341c29d4915SStanislav Mekhanoshin       }
342c29d4915SStanislav Mekhanoshin     }
343c29d4915SStanislav Mekhanoshin 
344c29d4915SStanislav Mekhanoshin     if (!Success) {
345*c155a944SJay Foad       for (unsigned I = 0; I < Info->VAddrOperands; ++I)
3466e85c3d5SMircea Trofin         if (VRM->hasPhys(Intervals[I]->reg()))
347c29d4915SStanislav Mekhanoshin           LRM->unassign(*Intervals[I]);
348c29d4915SStanislav Mekhanoshin 
349*c155a944SJay Foad       for (unsigned I = 0; I < Info->VAddrOperands; ++I)
350c29d4915SStanislav Mekhanoshin         LRM->assign(*Intervals[I], OrigRegs[I]);
351c29d4915SStanislav Mekhanoshin 
352c29d4915SStanislav Mekhanoshin       continue;
353c29d4915SStanislav Mekhanoshin     }
354c29d4915SStanislav Mekhanoshin 
355c29d4915SStanislav Mekhanoshin     C.second = true;
356c29d4915SStanislav Mekhanoshin     ++NumNSAConverted;
3576e85c3d5SMircea Trofin     LLVM_DEBUG(
3586e85c3d5SMircea Trofin         dbgs() << "\tNew allocation:\t\t ["
3596e85c3d5SMircea Trofin                << llvm::printReg((VRM->getPhys(Intervals.front()->reg())), TRI)
360c29d4915SStanislav Mekhanoshin                << " : "
3616e85c3d5SMircea Trofin                << llvm::printReg((VRM->getPhys(Intervals.back()->reg())), TRI)
362c29d4915SStanislav Mekhanoshin                << "]\n");
363c29d4915SStanislav Mekhanoshin     Changed = true;
364c29d4915SStanislav Mekhanoshin   }
365c29d4915SStanislav Mekhanoshin 
366c29d4915SStanislav Mekhanoshin   return Changed;
367c29d4915SStanislav Mekhanoshin }
368