brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.7 KiB · 62172a0 Raw
298 lines · cpp
1//===-- GCNPreRAOptimizations.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-exception6//7//===----------------------------------------------------------------------===//8//9/// \file10/// This pass combines split register tuple initialization into a single pseudo:11///12///   undef %0.sub1:sreg_64 = S_MOV_B32 113///   %0.sub0:sreg_64 = S_MOV_B32 214/// =>15///   %0:sreg_64 = S_MOV_B64_IMM_PSEUDO 0x20000000116///17/// This is to allow rematerialization of a value instead of spilling. It is18/// supposed to be done after register coalescer to allow it to do its job and19/// before actual register allocation to allow rematerialization.20///21/// Right now the pass only handles 64 bit SGPRs with immediate initializers,22/// although the same shall be possible with other register classes and23/// instructions if necessary.24///25/// This pass also adds register allocation hints to COPY.26/// The hints will be post-processed by SIRegisterInfo::getRegAllocationHints.27/// When using True16, we often see COPY moving a 16-bit value between a VGPR_3228/// and a VGPR_16. If we use the VGPR_16 that corresponds to the lo16 bits of29/// the VGPR_32, the COPY can be completely eliminated.30///31//===----------------------------------------------------------------------===//32 33#include "GCNPreRAOptimizations.h"34#include "AMDGPU.h"35#include "GCNSubtarget.h"36#include "MCTargetDesc/AMDGPUMCTargetDesc.h"37#include "SIRegisterInfo.h"38#include "llvm/CodeGen/LiveIntervals.h"39#include "llvm/CodeGen/MachineFunctionPass.h"40#include "llvm/InitializePasses.h"41 42using namespace llvm;43 44#define DEBUG_TYPE "amdgpu-pre-ra-optimizations"45 46namespace {47 48class GCNPreRAOptimizationsImpl {49private:50  const SIInstrInfo *TII;51  const SIRegisterInfo *TRI;52  MachineRegisterInfo *MRI;53  LiveIntervals *LIS;54 55  bool processReg(Register Reg);56 57public:58  GCNPreRAOptimizationsImpl(LiveIntervals *LS) : LIS(LS) {}59  bool run(MachineFunction &MF);60};61 62class GCNPreRAOptimizationsLegacy : public MachineFunctionPass {63public:64  static char ID;65 66  GCNPreRAOptimizationsLegacy() : MachineFunctionPass(ID) {67    initializeGCNPreRAOptimizationsLegacyPass(*PassRegistry::getPassRegistry());68  }69 70  bool runOnMachineFunction(MachineFunction &MF) override;71 72  StringRef getPassName() const override {73    return "AMDGPU Pre-RA optimizations";74  }75 76  void getAnalysisUsage(AnalysisUsage &AU) const override {77    AU.addRequired<LiveIntervalsWrapperPass>();78    AU.setPreservesAll();79    MachineFunctionPass::getAnalysisUsage(AU);80  }81};82} // End anonymous namespace.83 84INITIALIZE_PASS_BEGIN(GCNPreRAOptimizationsLegacy, DEBUG_TYPE,85                      "AMDGPU Pre-RA optimizations", false, false)86INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass)87INITIALIZE_PASS_END(GCNPreRAOptimizationsLegacy, DEBUG_TYPE,88                    "Pre-RA optimizations", false, false)89 90char GCNPreRAOptimizationsLegacy::ID = 0;91 92char &llvm::GCNPreRAOptimizationsID = GCNPreRAOptimizationsLegacy::ID;93 94FunctionPass *llvm::createGCNPreRAOptimizationsLegacyPass() {95  return new GCNPreRAOptimizationsLegacy();96}97 98bool GCNPreRAOptimizationsImpl::processReg(Register Reg) {99  MachineInstr *Def0 = nullptr;100  MachineInstr *Def1 = nullptr;101  uint64_t Init = 0;102  bool Changed = false;103  SmallSet<Register, 32> ModifiedRegs;104  bool IsAGPRDst = TRI->isAGPRClass(MRI->getRegClass(Reg));105 106  for (MachineInstr &I : MRI->def_instructions(Reg)) {107    switch (I.getOpcode()) {108    default:109      return false;110    case AMDGPU::V_ACCVGPR_WRITE_B32_e64:111      break;112    case AMDGPU::COPY: {113      // Some subtargets cannot do an AGPR to AGPR copy directly, and need an114      // intermdiate temporary VGPR register. Try to find the defining115      // accvgpr_write to avoid temporary registers.116 117      if (!IsAGPRDst)118        return false;119 120      Register SrcReg = I.getOperand(1).getReg();121 122      if (!SrcReg.isVirtual())123        break;124 125      // Check if source of copy is from another AGPR.126      bool IsAGPRSrc = TRI->isAGPRClass(MRI->getRegClass(SrcReg));127      if (!IsAGPRSrc)128        break;129 130      // def_instructions() does not look at subregs so it may give us a131      // different instruction that defines the same vreg but different subreg132      // so we have to manually check subreg.133      Register SrcSubReg = I.getOperand(1).getSubReg();134      for (auto &Def : MRI->def_instructions(SrcReg)) {135        if (SrcSubReg != Def.getOperand(0).getSubReg())136          continue;137 138        if (Def.getOpcode() == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {139          const MachineOperand &DefSrcMO = Def.getOperand(1);140 141          // Immediates are not an issue and can be propagated in142          // postrapseudos pass. Only handle cases where defining143          // accvgpr_write source is a vreg.144          if (DefSrcMO.isReg() && DefSrcMO.getReg().isVirtual()) {145            // Propagate source reg of accvgpr write to this copy instruction146            I.getOperand(1).setReg(DefSrcMO.getReg());147            I.getOperand(1).setSubReg(DefSrcMO.getSubReg());148 149            // Reg uses were changed, collect unique set of registers to update150            // live intervals at the end.151            ModifiedRegs.insert(DefSrcMO.getReg());152            ModifiedRegs.insert(SrcReg);153 154            Changed = true;155          }156 157          // Found the defining accvgpr_write, stop looking any further.158          break;159        }160      }161      break;162    }163    case AMDGPU::S_MOV_B32:164      if (I.getOperand(0).getReg() != Reg || !I.getOperand(1).isImm() ||165          I.getNumOperands() != 2)166        return false;167 168      switch (I.getOperand(0).getSubReg()) {169      default:170        return false;171      case AMDGPU::sub0:172        if (Def0)173          return false;174        Def0 = &I;175        Init |= Lo_32(I.getOperand(1).getImm());176        break;177      case AMDGPU::sub1:178        if (Def1)179          return false;180        Def1 = &I;181        Init |= static_cast<uint64_t>(I.getOperand(1).getImm()) << 32;182        break;183      }184      break;185    }186  }187 188  // For AGPR reg, check if live intervals need to be updated.189  if (IsAGPRDst) {190    if (Changed) {191      for (Register RegToUpdate : ModifiedRegs) {192        LIS->removeInterval(RegToUpdate);193        LIS->createAndComputeVirtRegInterval(RegToUpdate);194      }195    }196 197    return Changed;198  }199 200  // For SGPR reg, check if we can combine instructions.201  if (!Def0 || !Def1 || Def0->getParent() != Def1->getParent())202    return Changed;203 204  LLVM_DEBUG(dbgs() << "Combining:\n  " << *Def0 << "  " << *Def1205                    << "    =>\n");206 207  if (SlotIndex::isEarlierInstr(LIS->getInstructionIndex(*Def1),208                                LIS->getInstructionIndex(*Def0)))209    std::swap(Def0, Def1);210 211  LIS->RemoveMachineInstrFromMaps(*Def0);212  LIS->RemoveMachineInstrFromMaps(*Def1);213  auto NewI = BuildMI(*Def0->getParent(), *Def0, Def0->getDebugLoc(),214                      TII->get(AMDGPU::S_MOV_B64_IMM_PSEUDO), Reg)215                  .addImm(Init);216 217  Def0->eraseFromParent();218  Def1->eraseFromParent();219  LIS->InsertMachineInstrInMaps(*NewI);220  LIS->removeInterval(Reg);221  LIS->createAndComputeVirtRegInterval(Reg);222 223  LLVM_DEBUG(dbgs() << "  " << *NewI);224 225  return true;226}227 228bool GCNPreRAOptimizationsLegacy::runOnMachineFunction(MachineFunction &MF) {229  if (skipFunction(MF.getFunction()))230    return false;231  LiveIntervals *LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS();232  return GCNPreRAOptimizationsImpl(LIS).run(MF);233}234 235PreservedAnalyses236GCNPreRAOptimizationsPass::run(MachineFunction &MF,237                               MachineFunctionAnalysisManager &MFAM) {238  LiveIntervals *LIS = &MFAM.getResult<LiveIntervalsAnalysis>(MF);239  GCNPreRAOptimizationsImpl(LIS).run(MF);240  return PreservedAnalyses::all();241}242 243bool GCNPreRAOptimizationsImpl::run(MachineFunction &MF) {244  const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();245  TII = ST.getInstrInfo();246  MRI = &MF.getRegInfo();247  TRI = ST.getRegisterInfo();248 249  bool Changed = false;250 251  for (unsigned I = 0, E = MRI->getNumVirtRegs(); I != E; ++I) {252    Register Reg = Register::index2VirtReg(I);253    if (!LIS->hasInterval(Reg))254      continue;255    const TargetRegisterClass *RC = MRI->getRegClass(Reg);256    if ((RC->MC->getSizeInBits() != 64 || !TRI->isSGPRClass(RC)) &&257        (ST.hasGFX90AInsts() || !TRI->isAGPRClass(RC)))258      continue;259 260    Changed |= processReg(Reg);261  }262 263  if (!ST.useRealTrue16Insts())264    return Changed;265 266  // Add RA hints to improve True16 COPY elimination.267  for (const MachineBasicBlock &MBB : MF) {268    for (const MachineInstr &MI : MBB) {269      if (MI.getOpcode() != AMDGPU::COPY)270        continue;271      Register Dst = MI.getOperand(0).getReg();272      Register Src = MI.getOperand(1).getReg();273      if (Dst.isVirtual() &&274          MRI->getRegClass(Dst) == &AMDGPU::VGPR_16RegClass &&275          Src.isPhysical() &&276          TRI->getRegClassForReg(*MRI, Src) == &AMDGPU::VGPR_32RegClass)277        MRI->setRegAllocationHint(Dst, 0, TRI->getSubReg(Src, AMDGPU::lo16));278      if (Src.isVirtual() &&279          MRI->getRegClass(Src) == &AMDGPU::VGPR_16RegClass &&280          Dst.isPhysical() &&281          TRI->getRegClassForReg(*MRI, Dst) == &AMDGPU::VGPR_32RegClass)282        MRI->setRegAllocationHint(Src, 0, TRI->getSubReg(Dst, AMDGPU::lo16));283      if (!Dst.isVirtual() || !Src.isVirtual())284        continue;285      if (MRI->getRegClass(Dst) == &AMDGPU::VGPR_32RegClass &&286          MRI->getRegClass(Src) == &AMDGPU::VGPR_16RegClass) {287        MRI->setRegAllocationHint(Dst, AMDGPURI::Size32, Src);288        MRI->setRegAllocationHint(Src, AMDGPURI::Size16, Dst);289      }290      if (MRI->getRegClass(Dst) == &AMDGPU::VGPR_16RegClass &&291          MRI->getRegClass(Src) == &AMDGPU::VGPR_32RegClass)292        MRI->setRegAllocationHint(Dst, AMDGPURI::Size16, Src);293    }294  }295 296  return Changed;297}298