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