brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.5 KiB · b03d50f Raw
311 lines · cpp
1//===- AMDGPUResourceUsageAnalysis.h ---- analysis of resources -----------===//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/// \brief Analyzes how many registers and other resources are used by11/// functions.12///13/// The results of this analysis are used to fill the register usage, flat14/// usage, etc. into hardware registers.15///16//===----------------------------------------------------------------------===//17 18#include "AMDGPUResourceUsageAnalysis.h"19#include "AMDGPU.h"20#include "GCNSubtarget.h"21#include "SIMachineFunctionInfo.h"22#include "llvm/CodeGen/MachineFrameInfo.h"23#include "llvm/CodeGen/MachineModuleInfo.h"24#include "llvm/CodeGen/TargetPassConfig.h"25#include "llvm/IR/GlobalValue.h"26#include "llvm/Target/TargetMachine.h"27 28using namespace llvm;29using namespace llvm::AMDGPU;30 31#define DEBUG_TYPE "amdgpu-resource-usage"32 33char llvm::AMDGPUResourceUsageAnalysisWrapperPass::ID = 0;34char &llvm::AMDGPUResourceUsageAnalysisID =35    AMDGPUResourceUsageAnalysisWrapperPass::ID;36 37// In code object v4 and older, we need to tell the runtime some amount ahead of38// time if we don't know the true stack size. Assume a smaller number if this is39// only due to dynamic / non-entry block allocas.40static cl::opt<uint32_t> clAssumedStackSizeForExternalCall(41    "amdgpu-assume-external-call-stack-size",42    cl::desc("Assumed stack use of any external call (in bytes)"), cl::Hidden,43    cl::init(16384));44 45static cl::opt<uint32_t> clAssumedStackSizeForDynamicSizeObjects(46    "amdgpu-assume-dynamic-stack-object-size",47    cl::desc("Assumed extra stack use if there are any "48             "variable sized objects (in bytes)"),49    cl::Hidden, cl::init(4096));50 51INITIALIZE_PASS(AMDGPUResourceUsageAnalysisWrapperPass, DEBUG_TYPE,52                "Function register usage analysis", true, true)53 54static const Function *getCalleeFunction(const MachineOperand &Op) {55  if (Op.isImm()) {56    assert(Op.getImm() == 0);57    return nullptr;58  }59  return cast<Function>(Op.getGlobal()->stripPointerCastsAndAliases());60}61 62static bool hasAnyNonFlatUseOfReg(const MachineRegisterInfo &MRI,63                                  const SIInstrInfo &TII, unsigned Reg) {64  for (const MachineOperand &UseOp : MRI.reg_operands(Reg)) {65    if (!UseOp.isImplicit() || !TII.isFLAT(*UseOp.getParent()))66      return true;67  }68 69  return false;70}71 72bool AMDGPUResourceUsageAnalysisWrapperPass::runOnMachineFunction(73    MachineFunction &MF) {74  auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();75  if (!TPC)76    return false;77 78  const TargetMachine &TM = TPC->getTM<TargetMachine>();79  const MCSubtargetInfo &STI = *TM.getMCSubtargetInfo();80 81  // By default, for code object v5 and later, track only the minimum scratch82  // size83  uint32_t AssumedStackSizeForDynamicSizeObjects =84      clAssumedStackSizeForDynamicSizeObjects;85  uint32_t AssumedStackSizeForExternalCall = clAssumedStackSizeForExternalCall;86  if (AMDGPU::getAMDHSACodeObjectVersion(*MF.getFunction().getParent()) >=87          AMDGPU::AMDHSA_COV5 ||88      STI.getTargetTriple().getOS() == Triple::AMDPAL) {89    if (!clAssumedStackSizeForDynamicSizeObjects.getNumOccurrences())90      AssumedStackSizeForDynamicSizeObjects = 0;91    if (!clAssumedStackSizeForExternalCall.getNumOccurrences())92      AssumedStackSizeForExternalCall = 0;93  }94 95  ResourceInfo = AMDGPUResourceUsageAnalysisImpl().analyzeResourceUsage(96      MF, AssumedStackSizeForDynamicSizeObjects,97      AssumedStackSizeForExternalCall);98 99  return false;100}101 102AnalysisKey AMDGPUResourceUsageAnalysis::Key;103AMDGPUResourceUsageAnalysis::Result104AMDGPUResourceUsageAnalysis::run(MachineFunction &MF,105                                 MachineFunctionAnalysisManager &MFAM) {106  const MCSubtargetInfo &STI = *TM.getMCSubtargetInfo();107 108  // By default, for code object v5 and later, track only the minimum scratch109  // size110  uint32_t AssumedStackSizeForDynamicSizeObjects =111      clAssumedStackSizeForDynamicSizeObjects;112  uint32_t AssumedStackSizeForExternalCall = clAssumedStackSizeForExternalCall;113  if (AMDGPU::getAMDHSACodeObjectVersion(*MF.getFunction().getParent()) >=114          AMDGPU::AMDHSA_COV5 ||115      STI.getTargetTriple().getOS() == Triple::AMDPAL) {116    if (!clAssumedStackSizeForDynamicSizeObjects.getNumOccurrences())117      AssumedStackSizeForDynamicSizeObjects = 0;118    if (!clAssumedStackSizeForExternalCall.getNumOccurrences())119      AssumedStackSizeForExternalCall = 0;120  }121 122  return AMDGPUResourceUsageAnalysisImpl().analyzeResourceUsage(123      MF, AssumedStackSizeForDynamicSizeObjects,124      AssumedStackSizeForExternalCall);125}126 127AMDGPUResourceUsageAnalysisImpl::SIFunctionResourceInfo128AMDGPUResourceUsageAnalysisImpl::analyzeResourceUsage(129    const MachineFunction &MF, uint32_t AssumedStackSizeForDynamicSizeObjects,130    uint32_t AssumedStackSizeForExternalCall) const {131  SIFunctionResourceInfo Info;132 133  const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();134  const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();135  const MachineFrameInfo &FrameInfo = MF.getFrameInfo();136  const MachineRegisterInfo &MRI = MF.getRegInfo();137  const SIInstrInfo *TII = ST.getInstrInfo();138  const SIRegisterInfo &TRI = TII->getRegisterInfo();139 140  Info.UsesFlatScratch = MRI.isPhysRegUsed(AMDGPU::FLAT_SCR_LO) ||141                         MRI.isPhysRegUsed(AMDGPU::FLAT_SCR_HI) ||142                         MRI.isLiveIn(MFI->getPreloadedReg(143                             AMDGPUFunctionArgInfo::FLAT_SCRATCH_INIT));144 145  Info.NumNamedBarrier = MFI->getNumNamedBarriers();146 147  // Even if FLAT_SCRATCH is implicitly used, it has no effect if flat148  // instructions aren't used to access the scratch buffer. Inline assembly may149  // need it though.150  //151  // If we only have implicit uses of flat_scr on flat instructions, it is not152  // really needed.153  if (Info.UsesFlatScratch && !MFI->getUserSGPRInfo().hasFlatScratchInit() &&154      (!hasAnyNonFlatUseOfReg(MRI, *TII, AMDGPU::FLAT_SCR) &&155       !hasAnyNonFlatUseOfReg(MRI, *TII, AMDGPU::FLAT_SCR_LO) &&156       !hasAnyNonFlatUseOfReg(MRI, *TII, AMDGPU::FLAT_SCR_HI))) {157    Info.UsesFlatScratch = false;158  }159 160  Info.PrivateSegmentSize = FrameInfo.getStackSize();161 162  // Assume a big number if there are any unknown sized objects.163  Info.HasDynamicallySizedStack = FrameInfo.hasVarSizedObjects();164  if (Info.HasDynamicallySizedStack)165    Info.PrivateSegmentSize += AssumedStackSizeForDynamicSizeObjects;166 167  if (MFI->isStackRealigned())168    Info.PrivateSegmentSize += FrameInfo.getMaxAlign().value();169 170  Info.UsesVCC =171      MRI.isPhysRegUsed(AMDGPU::VCC_LO) || MRI.isPhysRegUsed(AMDGPU::VCC_HI);172  Info.NumExplicitSGPR = TRI.getNumUsedPhysRegs(MRI, AMDGPU::SGPR_32RegClass,173                                                /*IncludeCalls=*/false);174  if (ST.hasMAIInsts())175    Info.NumAGPR = TRI.getNumUsedPhysRegs(MRI, AMDGPU::AGPR_32RegClass,176                                          /*IncludeCalls=*/false);177 178  // If there are no calls, MachineRegisterInfo can tell us the used register179  // count easily.180  // A tail call isn't considered a call for MachineFrameInfo's purposes.181  if (!FrameInfo.hasCalls() && !FrameInfo.hasTailCall()) {182    Info.NumVGPR = TRI.getNumUsedPhysRegs(MRI, AMDGPU::VGPR_32RegClass,183                                          /*IncludeCalls=*/false);184    return Info;185  }186 187  int32_t MaxVGPR = -1;188  Info.CalleeSegmentSize = 0;189 190  for (const MachineBasicBlock &MBB : MF) {191    for (const MachineInstr &MI : MBB) {192      for (unsigned I = 0; I < MI.getNumOperands(); ++I) {193        const MachineOperand &MO = MI.getOperand(I);194 195        if (!MO.isReg())196          continue;197 198        Register Reg = MO.getReg();199        switch (Reg) {200        case AMDGPU::NoRegister:201          assert(MI.isDebugInstr() &&202                 "Instruction uses invalid noreg register");203          continue;204 205        case AMDGPU::XNACK_MASK:206        case AMDGPU::XNACK_MASK_LO:207        case AMDGPU::XNACK_MASK_HI:208          llvm_unreachable("xnack_mask registers should not be used");209 210        case AMDGPU::LDS_DIRECT:211          llvm_unreachable("lds_direct register should not be used");212 213        case AMDGPU::TBA:214        case AMDGPU::TBA_LO:215        case AMDGPU::TBA_HI:216        case AMDGPU::TMA:217        case AMDGPU::TMA_LO:218        case AMDGPU::TMA_HI:219          llvm_unreachable("trap handler registers should not be used");220 221        case AMDGPU::SRC_VCCZ:222          llvm_unreachable("src_vccz register should not be used");223 224        case AMDGPU::SRC_EXECZ:225          llvm_unreachable("src_execz register should not be used");226 227        case AMDGPU::SRC_SCC:228          llvm_unreachable("src_scc register should not be used");229 230        default:231          break;232        }233 234        const TargetRegisterClass *RC = TRI.getPhysRegBaseClass(Reg);235        assert((!RC || TRI.isVGPRClass(RC) || TRI.isSGPRClass(RC) ||236                TRI.isAGPRClass(RC) || AMDGPU::TTMP_32RegClass.contains(Reg) ||237                AMDGPU::TTMP_64RegClass.contains(Reg) ||238                AMDGPU::TTMP_128RegClass.contains(Reg) ||239                AMDGPU::TTMP_256RegClass.contains(Reg) ||240                AMDGPU::TTMP_512RegClass.contains(Reg)) &&241               "Unknown register class");242 243        if (!RC || !TRI.isVGPRClass(RC))244          continue;245 246        if (MI.isCall() || MI.isMetaInstruction())247          continue;248 249        unsigned Width = divideCeil(TRI.getRegSizeInBits(*RC), 32);250        unsigned HWReg = TRI.getHWRegIndex(Reg);251        int MaxUsed = HWReg + Width - 1;252        MaxVGPR = std::max(MaxUsed, MaxVGPR);253      }254 255      if (MI.isCall()) {256        // Pseudo used just to encode the underlying global. Is there a better257        // way to track this?258 259        const MachineOperand *CalleeOp =260            TII->getNamedOperand(MI, AMDGPU::OpName::callee);261 262        const Function *Callee = getCalleeFunction(*CalleeOp);263 264        auto isSameFunction = [](const MachineFunction &MF, const Function *F) {265          return F == &MF.getFunction();266        };267 268        if (Callee && !isSameFunction(MF, Callee))269          Info.Callees.push_back(Callee);270 271        bool IsIndirect = !Callee || Callee->isDeclaration();272 273        // FIXME: Call site could have norecurse on it274        if (!Callee || !Callee->doesNotRecurse()) {275          Info.HasRecursion = true;276 277          // TODO: If we happen to know there is no stack usage in the278          // callgraph, we don't need to assume an infinitely growing stack.279          if (!MI.isReturn()) {280            // We don't need to assume an unknown stack size for tail calls.281 282            // FIXME: This only benefits in the case where the kernel does not283            // directly call the tail called function. If a kernel directly284            // calls a tail recursive function, we'll assume maximum stack size285            // based on the regular call instruction.286            Info.CalleeSegmentSize = std::max(287                Info.CalleeSegmentSize,288                static_cast<uint64_t>(AssumedStackSizeForExternalCall));289          }290        }291 292        if (IsIndirect) {293          Info.CalleeSegmentSize =294              std::max(Info.CalleeSegmentSize,295                       static_cast<uint64_t>(AssumedStackSizeForExternalCall));296 297          // Register usage of indirect calls gets handled later298          Info.UsesVCC = true;299          Info.UsesFlatScratch = ST.hasFlatAddressSpace();300          Info.HasDynamicallySizedStack = true;301          Info.HasIndirectCall = true;302        }303      }304    }305  }306 307  Info.NumVGPR = MaxVGPR + 1;308 309  return Info;310}311