1*0b57cec5SDimitry Andric //==- SIMachineFunctionInfo.h - SIMachineFunctionInfo interface --*- C++ -*-==// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric /// \file 10*0b57cec5SDimitry Andric // 11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 12*0b57cec5SDimitry Andric 13*0b57cec5SDimitry Andric #ifndef LLVM_LIB_TARGET_AMDGPU_SIMACHINEFUNCTIONINFO_H 14*0b57cec5SDimitry Andric #define LLVM_LIB_TARGET_AMDGPU_SIMACHINEFUNCTIONINFO_H 15*0b57cec5SDimitry Andric 16*0b57cec5SDimitry Andric #include "AMDGPUArgumentUsageInfo.h" 17*0b57cec5SDimitry Andric #include "AMDGPUMachineFunction.h" 18*0b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 19*0b57cec5SDimitry Andric #include "SIInstrInfo.h" 20*0b57cec5SDimitry Andric #include "SIRegisterInfo.h" 21*0b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 22*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 23*0b57cec5SDimitry Andric #include "llvm/ADT/Optional.h" 24*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 25*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 26*0b57cec5SDimitry Andric #include "llvm/ADT/SparseBitVector.h" 27*0b57cec5SDimitry Andric #include "llvm/CodeGen/MIRYamlMapping.h" 28*0b57cec5SDimitry Andric #include "llvm/CodeGen/PseudoSourceValue.h" 29*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 30*0b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 31*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 32*0b57cec5SDimitry Andric #include <array> 33*0b57cec5SDimitry Andric #include <cassert> 34*0b57cec5SDimitry Andric #include <utility> 35*0b57cec5SDimitry Andric #include <vector> 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric namespace llvm { 38*0b57cec5SDimitry Andric 39*0b57cec5SDimitry Andric class MachineFrameInfo; 40*0b57cec5SDimitry Andric class MachineFunction; 41*0b57cec5SDimitry Andric class TargetRegisterClass; 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric class AMDGPUPseudoSourceValue : public PseudoSourceValue { 44*0b57cec5SDimitry Andric public: 45*0b57cec5SDimitry Andric enum AMDGPUPSVKind : unsigned { 46*0b57cec5SDimitry Andric PSVBuffer = PseudoSourceValue::TargetCustom, 47*0b57cec5SDimitry Andric PSVImage, 48*0b57cec5SDimitry Andric GWSResource 49*0b57cec5SDimitry Andric }; 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric protected: 52*0b57cec5SDimitry Andric AMDGPUPseudoSourceValue(unsigned Kind, const TargetInstrInfo &TII) 53*0b57cec5SDimitry Andric : PseudoSourceValue(Kind, TII) {} 54*0b57cec5SDimitry Andric 55*0b57cec5SDimitry Andric public: 56*0b57cec5SDimitry Andric bool isConstant(const MachineFrameInfo *) const override { 57*0b57cec5SDimitry Andric // This should probably be true for most images, but we will start by being 58*0b57cec5SDimitry Andric // conservative. 59*0b57cec5SDimitry Andric return false; 60*0b57cec5SDimitry Andric } 61*0b57cec5SDimitry Andric 62*0b57cec5SDimitry Andric bool isAliased(const MachineFrameInfo *) const override { 63*0b57cec5SDimitry Andric return true; 64*0b57cec5SDimitry Andric } 65*0b57cec5SDimitry Andric 66*0b57cec5SDimitry Andric bool mayAlias(const MachineFrameInfo *) const override { 67*0b57cec5SDimitry Andric return true; 68*0b57cec5SDimitry Andric } 69*0b57cec5SDimitry Andric }; 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric class AMDGPUBufferPseudoSourceValue final : public AMDGPUPseudoSourceValue { 72*0b57cec5SDimitry Andric public: 73*0b57cec5SDimitry Andric explicit AMDGPUBufferPseudoSourceValue(const TargetInstrInfo &TII) 74*0b57cec5SDimitry Andric : AMDGPUPseudoSourceValue(PSVBuffer, TII) {} 75*0b57cec5SDimitry Andric 76*0b57cec5SDimitry Andric static bool classof(const PseudoSourceValue *V) { 77*0b57cec5SDimitry Andric return V->kind() == PSVBuffer; 78*0b57cec5SDimitry Andric } 79*0b57cec5SDimitry Andric }; 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric class AMDGPUImagePseudoSourceValue final : public AMDGPUPseudoSourceValue { 82*0b57cec5SDimitry Andric public: 83*0b57cec5SDimitry Andric // TODO: Is the img rsrc useful? 84*0b57cec5SDimitry Andric explicit AMDGPUImagePseudoSourceValue(const TargetInstrInfo &TII) 85*0b57cec5SDimitry Andric : AMDGPUPseudoSourceValue(PSVImage, TII) {} 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric static bool classof(const PseudoSourceValue *V) { 88*0b57cec5SDimitry Andric return V->kind() == PSVImage; 89*0b57cec5SDimitry Andric } 90*0b57cec5SDimitry Andric }; 91*0b57cec5SDimitry Andric 92*0b57cec5SDimitry Andric class AMDGPUGWSResourcePseudoSourceValue final : public AMDGPUPseudoSourceValue { 93*0b57cec5SDimitry Andric public: 94*0b57cec5SDimitry Andric explicit AMDGPUGWSResourcePseudoSourceValue(const TargetInstrInfo &TII) 95*0b57cec5SDimitry Andric : AMDGPUPseudoSourceValue(GWSResource, TII) {} 96*0b57cec5SDimitry Andric 97*0b57cec5SDimitry Andric static bool classof(const PseudoSourceValue *V) { 98*0b57cec5SDimitry Andric return V->kind() == GWSResource; 99*0b57cec5SDimitry Andric } 100*0b57cec5SDimitry Andric 101*0b57cec5SDimitry Andric // These are inaccessible memory from IR. 102*0b57cec5SDimitry Andric bool isAliased(const MachineFrameInfo *) const override { 103*0b57cec5SDimitry Andric return false; 104*0b57cec5SDimitry Andric } 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric // These are inaccessible memory from IR. 107*0b57cec5SDimitry Andric bool mayAlias(const MachineFrameInfo *) const override { 108*0b57cec5SDimitry Andric return false; 109*0b57cec5SDimitry Andric } 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric void printCustom(raw_ostream &OS) const override { 112*0b57cec5SDimitry Andric OS << "GWSResource"; 113*0b57cec5SDimitry Andric } 114*0b57cec5SDimitry Andric }; 115*0b57cec5SDimitry Andric 116*0b57cec5SDimitry Andric namespace yaml { 117*0b57cec5SDimitry Andric 118*0b57cec5SDimitry Andric struct SIArgument { 119*0b57cec5SDimitry Andric bool IsRegister; 120*0b57cec5SDimitry Andric union { 121*0b57cec5SDimitry Andric StringValue RegisterName; 122*0b57cec5SDimitry Andric unsigned StackOffset; 123*0b57cec5SDimitry Andric }; 124*0b57cec5SDimitry Andric Optional<unsigned> Mask; 125*0b57cec5SDimitry Andric 126*0b57cec5SDimitry Andric // Default constructor, which creates a stack argument. 127*0b57cec5SDimitry Andric SIArgument() : IsRegister(false), StackOffset(0) {} 128*0b57cec5SDimitry Andric SIArgument(const SIArgument &Other) { 129*0b57cec5SDimitry Andric IsRegister = Other.IsRegister; 130*0b57cec5SDimitry Andric if (IsRegister) { 131*0b57cec5SDimitry Andric ::new ((void *)std::addressof(RegisterName)) 132*0b57cec5SDimitry Andric StringValue(Other.RegisterName); 133*0b57cec5SDimitry Andric } else 134*0b57cec5SDimitry Andric StackOffset = Other.StackOffset; 135*0b57cec5SDimitry Andric Mask = Other.Mask; 136*0b57cec5SDimitry Andric } 137*0b57cec5SDimitry Andric SIArgument &operator=(const SIArgument &Other) { 138*0b57cec5SDimitry Andric IsRegister = Other.IsRegister; 139*0b57cec5SDimitry Andric if (IsRegister) { 140*0b57cec5SDimitry Andric ::new ((void *)std::addressof(RegisterName)) 141*0b57cec5SDimitry Andric StringValue(Other.RegisterName); 142*0b57cec5SDimitry Andric } else 143*0b57cec5SDimitry Andric StackOffset = Other.StackOffset; 144*0b57cec5SDimitry Andric Mask = Other.Mask; 145*0b57cec5SDimitry Andric return *this; 146*0b57cec5SDimitry Andric } 147*0b57cec5SDimitry Andric ~SIArgument() { 148*0b57cec5SDimitry Andric if (IsRegister) 149*0b57cec5SDimitry Andric RegisterName.~StringValue(); 150*0b57cec5SDimitry Andric } 151*0b57cec5SDimitry Andric 152*0b57cec5SDimitry Andric // Helper to create a register or stack argument. 153*0b57cec5SDimitry Andric static inline SIArgument createArgument(bool IsReg) { 154*0b57cec5SDimitry Andric if (IsReg) 155*0b57cec5SDimitry Andric return SIArgument(IsReg); 156*0b57cec5SDimitry Andric return SIArgument(); 157*0b57cec5SDimitry Andric } 158*0b57cec5SDimitry Andric 159*0b57cec5SDimitry Andric private: 160*0b57cec5SDimitry Andric // Construct a register argument. 161*0b57cec5SDimitry Andric SIArgument(bool) : IsRegister(true), RegisterName() {} 162*0b57cec5SDimitry Andric }; 163*0b57cec5SDimitry Andric 164*0b57cec5SDimitry Andric template <> struct MappingTraits<SIArgument> { 165*0b57cec5SDimitry Andric static void mapping(IO &YamlIO, SIArgument &A) { 166*0b57cec5SDimitry Andric if (YamlIO.outputting()) { 167*0b57cec5SDimitry Andric if (A.IsRegister) 168*0b57cec5SDimitry Andric YamlIO.mapRequired("reg", A.RegisterName); 169*0b57cec5SDimitry Andric else 170*0b57cec5SDimitry Andric YamlIO.mapRequired("offset", A.StackOffset); 171*0b57cec5SDimitry Andric } else { 172*0b57cec5SDimitry Andric auto Keys = YamlIO.keys(); 173*0b57cec5SDimitry Andric if (is_contained(Keys, "reg")) { 174*0b57cec5SDimitry Andric A = SIArgument::createArgument(true); 175*0b57cec5SDimitry Andric YamlIO.mapRequired("reg", A.RegisterName); 176*0b57cec5SDimitry Andric } else if (is_contained(Keys, "offset")) 177*0b57cec5SDimitry Andric YamlIO.mapRequired("offset", A.StackOffset); 178*0b57cec5SDimitry Andric else 179*0b57cec5SDimitry Andric YamlIO.setError("missing required key 'reg' or 'offset'"); 180*0b57cec5SDimitry Andric } 181*0b57cec5SDimitry Andric YamlIO.mapOptional("mask", A.Mask); 182*0b57cec5SDimitry Andric } 183*0b57cec5SDimitry Andric static const bool flow = true; 184*0b57cec5SDimitry Andric }; 185*0b57cec5SDimitry Andric 186*0b57cec5SDimitry Andric struct SIArgumentInfo { 187*0b57cec5SDimitry Andric Optional<SIArgument> PrivateSegmentBuffer; 188*0b57cec5SDimitry Andric Optional<SIArgument> DispatchPtr; 189*0b57cec5SDimitry Andric Optional<SIArgument> QueuePtr; 190*0b57cec5SDimitry Andric Optional<SIArgument> KernargSegmentPtr; 191*0b57cec5SDimitry Andric Optional<SIArgument> DispatchID; 192*0b57cec5SDimitry Andric Optional<SIArgument> FlatScratchInit; 193*0b57cec5SDimitry Andric Optional<SIArgument> PrivateSegmentSize; 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric Optional<SIArgument> WorkGroupIDX; 196*0b57cec5SDimitry Andric Optional<SIArgument> WorkGroupIDY; 197*0b57cec5SDimitry Andric Optional<SIArgument> WorkGroupIDZ; 198*0b57cec5SDimitry Andric Optional<SIArgument> WorkGroupInfo; 199*0b57cec5SDimitry Andric Optional<SIArgument> PrivateSegmentWaveByteOffset; 200*0b57cec5SDimitry Andric 201*0b57cec5SDimitry Andric Optional<SIArgument> ImplicitArgPtr; 202*0b57cec5SDimitry Andric Optional<SIArgument> ImplicitBufferPtr; 203*0b57cec5SDimitry Andric 204*0b57cec5SDimitry Andric Optional<SIArgument> WorkItemIDX; 205*0b57cec5SDimitry Andric Optional<SIArgument> WorkItemIDY; 206*0b57cec5SDimitry Andric Optional<SIArgument> WorkItemIDZ; 207*0b57cec5SDimitry Andric }; 208*0b57cec5SDimitry Andric 209*0b57cec5SDimitry Andric template <> struct MappingTraits<SIArgumentInfo> { 210*0b57cec5SDimitry Andric static void mapping(IO &YamlIO, SIArgumentInfo &AI) { 211*0b57cec5SDimitry Andric YamlIO.mapOptional("privateSegmentBuffer", AI.PrivateSegmentBuffer); 212*0b57cec5SDimitry Andric YamlIO.mapOptional("dispatchPtr", AI.DispatchPtr); 213*0b57cec5SDimitry Andric YamlIO.mapOptional("queuePtr", AI.QueuePtr); 214*0b57cec5SDimitry Andric YamlIO.mapOptional("kernargSegmentPtr", AI.KernargSegmentPtr); 215*0b57cec5SDimitry Andric YamlIO.mapOptional("dispatchID", AI.DispatchID); 216*0b57cec5SDimitry Andric YamlIO.mapOptional("flatScratchInit", AI.FlatScratchInit); 217*0b57cec5SDimitry Andric YamlIO.mapOptional("privateSegmentSize", AI.PrivateSegmentSize); 218*0b57cec5SDimitry Andric 219*0b57cec5SDimitry Andric YamlIO.mapOptional("workGroupIDX", AI.WorkGroupIDX); 220*0b57cec5SDimitry Andric YamlIO.mapOptional("workGroupIDY", AI.WorkGroupIDY); 221*0b57cec5SDimitry Andric YamlIO.mapOptional("workGroupIDZ", AI.WorkGroupIDZ); 222*0b57cec5SDimitry Andric YamlIO.mapOptional("workGroupInfo", AI.WorkGroupInfo); 223*0b57cec5SDimitry Andric YamlIO.mapOptional("privateSegmentWaveByteOffset", 224*0b57cec5SDimitry Andric AI.PrivateSegmentWaveByteOffset); 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric YamlIO.mapOptional("implicitArgPtr", AI.ImplicitArgPtr); 227*0b57cec5SDimitry Andric YamlIO.mapOptional("implicitBufferPtr", AI.ImplicitBufferPtr); 228*0b57cec5SDimitry Andric 229*0b57cec5SDimitry Andric YamlIO.mapOptional("workItemIDX", AI.WorkItemIDX); 230*0b57cec5SDimitry Andric YamlIO.mapOptional("workItemIDY", AI.WorkItemIDY); 231*0b57cec5SDimitry Andric YamlIO.mapOptional("workItemIDZ", AI.WorkItemIDZ); 232*0b57cec5SDimitry Andric } 233*0b57cec5SDimitry Andric }; 234*0b57cec5SDimitry Andric 235*0b57cec5SDimitry Andric // Default to default mode for default calling convention. 236*0b57cec5SDimitry Andric struct SIMode { 237*0b57cec5SDimitry Andric bool IEEE = true; 238*0b57cec5SDimitry Andric bool DX10Clamp = true; 239*0b57cec5SDimitry Andric 240*0b57cec5SDimitry Andric SIMode() = default; 241*0b57cec5SDimitry Andric 242*0b57cec5SDimitry Andric 243*0b57cec5SDimitry Andric SIMode(const AMDGPU::SIModeRegisterDefaults &Mode) { 244*0b57cec5SDimitry Andric IEEE = Mode.IEEE; 245*0b57cec5SDimitry Andric DX10Clamp = Mode.DX10Clamp; 246*0b57cec5SDimitry Andric } 247*0b57cec5SDimitry Andric 248*0b57cec5SDimitry Andric bool operator ==(const SIMode Other) const { 249*0b57cec5SDimitry Andric return IEEE == Other.IEEE && DX10Clamp == Other.DX10Clamp; 250*0b57cec5SDimitry Andric } 251*0b57cec5SDimitry Andric }; 252*0b57cec5SDimitry Andric 253*0b57cec5SDimitry Andric template <> struct MappingTraits<SIMode> { 254*0b57cec5SDimitry Andric static void mapping(IO &YamlIO, SIMode &Mode) { 255*0b57cec5SDimitry Andric YamlIO.mapOptional("ieee", Mode.IEEE, true); 256*0b57cec5SDimitry Andric YamlIO.mapOptional("dx10-clamp", Mode.DX10Clamp, true); 257*0b57cec5SDimitry Andric } 258*0b57cec5SDimitry Andric }; 259*0b57cec5SDimitry Andric 260*0b57cec5SDimitry Andric struct SIMachineFunctionInfo final : public yaml::MachineFunctionInfo { 261*0b57cec5SDimitry Andric uint64_t ExplicitKernArgSize = 0; 262*0b57cec5SDimitry Andric unsigned MaxKernArgAlign = 0; 263*0b57cec5SDimitry Andric unsigned LDSSize = 0; 264*0b57cec5SDimitry Andric bool IsEntryFunction = false; 265*0b57cec5SDimitry Andric bool NoSignedZerosFPMath = false; 266*0b57cec5SDimitry Andric bool MemoryBound = false; 267*0b57cec5SDimitry Andric bool WaveLimiter = false; 268*0b57cec5SDimitry Andric 269*0b57cec5SDimitry Andric StringValue ScratchRSrcReg = "$private_rsrc_reg"; 270*0b57cec5SDimitry Andric StringValue ScratchWaveOffsetReg = "$scratch_wave_offset_reg"; 271*0b57cec5SDimitry Andric StringValue FrameOffsetReg = "$fp_reg"; 272*0b57cec5SDimitry Andric StringValue StackPtrOffsetReg = "$sp_reg"; 273*0b57cec5SDimitry Andric 274*0b57cec5SDimitry Andric Optional<SIArgumentInfo> ArgInfo; 275*0b57cec5SDimitry Andric SIMode Mode; 276*0b57cec5SDimitry Andric 277*0b57cec5SDimitry Andric SIMachineFunctionInfo() = default; 278*0b57cec5SDimitry Andric SIMachineFunctionInfo(const llvm::SIMachineFunctionInfo &, 279*0b57cec5SDimitry Andric const TargetRegisterInfo &TRI); 280*0b57cec5SDimitry Andric 281*0b57cec5SDimitry Andric void mappingImpl(yaml::IO &YamlIO) override; 282*0b57cec5SDimitry Andric ~SIMachineFunctionInfo() = default; 283*0b57cec5SDimitry Andric }; 284*0b57cec5SDimitry Andric 285*0b57cec5SDimitry Andric template <> struct MappingTraits<SIMachineFunctionInfo> { 286*0b57cec5SDimitry Andric static void mapping(IO &YamlIO, SIMachineFunctionInfo &MFI) { 287*0b57cec5SDimitry Andric YamlIO.mapOptional("explicitKernArgSize", MFI.ExplicitKernArgSize, 288*0b57cec5SDimitry Andric UINT64_C(0)); 289*0b57cec5SDimitry Andric YamlIO.mapOptional("maxKernArgAlign", MFI.MaxKernArgAlign, 0u); 290*0b57cec5SDimitry Andric YamlIO.mapOptional("ldsSize", MFI.LDSSize, 0u); 291*0b57cec5SDimitry Andric YamlIO.mapOptional("isEntryFunction", MFI.IsEntryFunction, false); 292*0b57cec5SDimitry Andric YamlIO.mapOptional("noSignedZerosFPMath", MFI.NoSignedZerosFPMath, false); 293*0b57cec5SDimitry Andric YamlIO.mapOptional("memoryBound", MFI.MemoryBound, false); 294*0b57cec5SDimitry Andric YamlIO.mapOptional("waveLimiter", MFI.WaveLimiter, false); 295*0b57cec5SDimitry Andric YamlIO.mapOptional("scratchRSrcReg", MFI.ScratchRSrcReg, 296*0b57cec5SDimitry Andric StringValue("$private_rsrc_reg")); 297*0b57cec5SDimitry Andric YamlIO.mapOptional("scratchWaveOffsetReg", MFI.ScratchWaveOffsetReg, 298*0b57cec5SDimitry Andric StringValue("$scratch_wave_offset_reg")); 299*0b57cec5SDimitry Andric YamlIO.mapOptional("frameOffsetReg", MFI.FrameOffsetReg, 300*0b57cec5SDimitry Andric StringValue("$fp_reg")); 301*0b57cec5SDimitry Andric YamlIO.mapOptional("stackPtrOffsetReg", MFI.StackPtrOffsetReg, 302*0b57cec5SDimitry Andric StringValue("$sp_reg")); 303*0b57cec5SDimitry Andric YamlIO.mapOptional("argumentInfo", MFI.ArgInfo); 304*0b57cec5SDimitry Andric YamlIO.mapOptional("mode", MFI.Mode, SIMode()); 305*0b57cec5SDimitry Andric } 306*0b57cec5SDimitry Andric }; 307*0b57cec5SDimitry Andric 308*0b57cec5SDimitry Andric } // end namespace yaml 309*0b57cec5SDimitry Andric 310*0b57cec5SDimitry Andric /// This class keeps track of the SPI_SP_INPUT_ADDR config register, which 311*0b57cec5SDimitry Andric /// tells the hardware which interpolation parameters to load. 312*0b57cec5SDimitry Andric class SIMachineFunctionInfo final : public AMDGPUMachineFunction { 313*0b57cec5SDimitry Andric friend class GCNTargetMachine; 314*0b57cec5SDimitry Andric 315*0b57cec5SDimitry Andric unsigned TIDReg = AMDGPU::NoRegister; 316*0b57cec5SDimitry Andric 317*0b57cec5SDimitry Andric // Registers that may be reserved for spilling purposes. These may be the same 318*0b57cec5SDimitry Andric // as the input registers. 319*0b57cec5SDimitry Andric unsigned ScratchRSrcReg = AMDGPU::PRIVATE_RSRC_REG; 320*0b57cec5SDimitry Andric unsigned ScratchWaveOffsetReg = AMDGPU::SCRATCH_WAVE_OFFSET_REG; 321*0b57cec5SDimitry Andric 322*0b57cec5SDimitry Andric // This is the current function's incremented size from the kernel's scratch 323*0b57cec5SDimitry Andric // wave offset register. For an entry function, this is exactly the same as 324*0b57cec5SDimitry Andric // the ScratchWaveOffsetReg. 325*0b57cec5SDimitry Andric unsigned FrameOffsetReg = AMDGPU::FP_REG; 326*0b57cec5SDimitry Andric 327*0b57cec5SDimitry Andric // Top of the stack SGPR offset derived from the ScratchWaveOffsetReg. 328*0b57cec5SDimitry Andric unsigned StackPtrOffsetReg = AMDGPU::SP_REG; 329*0b57cec5SDimitry Andric 330*0b57cec5SDimitry Andric AMDGPUFunctionArgInfo ArgInfo; 331*0b57cec5SDimitry Andric 332*0b57cec5SDimitry Andric // State of MODE register, assumed FP mode. 333*0b57cec5SDimitry Andric AMDGPU::SIModeRegisterDefaults Mode; 334*0b57cec5SDimitry Andric 335*0b57cec5SDimitry Andric // Graphics info. 336*0b57cec5SDimitry Andric unsigned PSInputAddr = 0; 337*0b57cec5SDimitry Andric unsigned PSInputEnable = 0; 338*0b57cec5SDimitry Andric 339*0b57cec5SDimitry Andric /// Number of bytes of arguments this function has on the stack. If the callee 340*0b57cec5SDimitry Andric /// is expected to restore the argument stack this should be a multiple of 16, 341*0b57cec5SDimitry Andric /// all usable during a tail call. 342*0b57cec5SDimitry Andric /// 343*0b57cec5SDimitry Andric /// The alternative would forbid tail call optimisation in some cases: if we 344*0b57cec5SDimitry Andric /// want to transfer control from a function with 8-bytes of stack-argument 345*0b57cec5SDimitry Andric /// space to a function with 16-bytes then misalignment of this value would 346*0b57cec5SDimitry Andric /// make a stack adjustment necessary, which could not be undone by the 347*0b57cec5SDimitry Andric /// callee. 348*0b57cec5SDimitry Andric unsigned BytesInStackArgArea = 0; 349*0b57cec5SDimitry Andric 350*0b57cec5SDimitry Andric bool ReturnsVoid = true; 351*0b57cec5SDimitry Andric 352*0b57cec5SDimitry Andric // A pair of default/requested minimum/maximum flat work group sizes. 353*0b57cec5SDimitry Andric // Minimum - first, maximum - second. 354*0b57cec5SDimitry Andric std::pair<unsigned, unsigned> FlatWorkGroupSizes = {0, 0}; 355*0b57cec5SDimitry Andric 356*0b57cec5SDimitry Andric // A pair of default/requested minimum/maximum number of waves per execution 357*0b57cec5SDimitry Andric // unit. Minimum - first, maximum - second. 358*0b57cec5SDimitry Andric std::pair<unsigned, unsigned> WavesPerEU = {0, 0}; 359*0b57cec5SDimitry Andric 360*0b57cec5SDimitry Andric DenseMap<const Value *, 361*0b57cec5SDimitry Andric std::unique_ptr<const AMDGPUBufferPseudoSourceValue>> BufferPSVs; 362*0b57cec5SDimitry Andric DenseMap<const Value *, 363*0b57cec5SDimitry Andric std::unique_ptr<const AMDGPUImagePseudoSourceValue>> ImagePSVs; 364*0b57cec5SDimitry Andric std::unique_ptr<const AMDGPUGWSResourcePseudoSourceValue> GWSResourcePSV; 365*0b57cec5SDimitry Andric 366*0b57cec5SDimitry Andric private: 367*0b57cec5SDimitry Andric unsigned LDSWaveSpillSize = 0; 368*0b57cec5SDimitry Andric unsigned NumUserSGPRs = 0; 369*0b57cec5SDimitry Andric unsigned NumSystemSGPRs = 0; 370*0b57cec5SDimitry Andric 371*0b57cec5SDimitry Andric bool HasSpilledSGPRs = false; 372*0b57cec5SDimitry Andric bool HasSpilledVGPRs = false; 373*0b57cec5SDimitry Andric bool HasNonSpillStackObjects = false; 374*0b57cec5SDimitry Andric bool IsStackRealigned = false; 375*0b57cec5SDimitry Andric 376*0b57cec5SDimitry Andric unsigned NumSpilledSGPRs = 0; 377*0b57cec5SDimitry Andric unsigned NumSpilledVGPRs = 0; 378*0b57cec5SDimitry Andric 379*0b57cec5SDimitry Andric // Feature bits required for inputs passed in user SGPRs. 380*0b57cec5SDimitry Andric bool PrivateSegmentBuffer : 1; 381*0b57cec5SDimitry Andric bool DispatchPtr : 1; 382*0b57cec5SDimitry Andric bool QueuePtr : 1; 383*0b57cec5SDimitry Andric bool KernargSegmentPtr : 1; 384*0b57cec5SDimitry Andric bool DispatchID : 1; 385*0b57cec5SDimitry Andric bool FlatScratchInit : 1; 386*0b57cec5SDimitry Andric 387*0b57cec5SDimitry Andric // Feature bits required for inputs passed in system SGPRs. 388*0b57cec5SDimitry Andric bool WorkGroupIDX : 1; // Always initialized. 389*0b57cec5SDimitry Andric bool WorkGroupIDY : 1; 390*0b57cec5SDimitry Andric bool WorkGroupIDZ : 1; 391*0b57cec5SDimitry Andric bool WorkGroupInfo : 1; 392*0b57cec5SDimitry Andric bool PrivateSegmentWaveByteOffset : 1; 393*0b57cec5SDimitry Andric 394*0b57cec5SDimitry Andric bool WorkItemIDX : 1; // Always initialized. 395*0b57cec5SDimitry Andric bool WorkItemIDY : 1; 396*0b57cec5SDimitry Andric bool WorkItemIDZ : 1; 397*0b57cec5SDimitry Andric 398*0b57cec5SDimitry Andric // Private memory buffer 399*0b57cec5SDimitry Andric // Compute directly in sgpr[0:1] 400*0b57cec5SDimitry Andric // Other shaders indirect 64-bits at sgpr[0:1] 401*0b57cec5SDimitry Andric bool ImplicitBufferPtr : 1; 402*0b57cec5SDimitry Andric 403*0b57cec5SDimitry Andric // Pointer to where the ABI inserts special kernel arguments separate from the 404*0b57cec5SDimitry Andric // user arguments. This is an offset from the KernargSegmentPtr. 405*0b57cec5SDimitry Andric bool ImplicitArgPtr : 1; 406*0b57cec5SDimitry Andric 407*0b57cec5SDimitry Andric // The hard-wired high half of the address of the global information table 408*0b57cec5SDimitry Andric // for AMDPAL OS type. 0xffffffff represents no hard-wired high half, since 409*0b57cec5SDimitry Andric // current hardware only allows a 16 bit value. 410*0b57cec5SDimitry Andric unsigned GITPtrHigh; 411*0b57cec5SDimitry Andric 412*0b57cec5SDimitry Andric unsigned HighBitsOf32BitAddress; 413*0b57cec5SDimitry Andric unsigned GDSSize; 414*0b57cec5SDimitry Andric 415*0b57cec5SDimitry Andric // Current recorded maximum possible occupancy. 416*0b57cec5SDimitry Andric unsigned Occupancy; 417*0b57cec5SDimitry Andric 418*0b57cec5SDimitry Andric MCPhysReg getNextUserSGPR() const; 419*0b57cec5SDimitry Andric 420*0b57cec5SDimitry Andric MCPhysReg getNextSystemSGPR() const; 421*0b57cec5SDimitry Andric 422*0b57cec5SDimitry Andric public: 423*0b57cec5SDimitry Andric struct SpilledReg { 424*0b57cec5SDimitry Andric unsigned VGPR = 0; 425*0b57cec5SDimitry Andric int Lane = -1; 426*0b57cec5SDimitry Andric 427*0b57cec5SDimitry Andric SpilledReg() = default; 428*0b57cec5SDimitry Andric SpilledReg(unsigned R, int L) : VGPR (R), Lane (L) {} 429*0b57cec5SDimitry Andric 430*0b57cec5SDimitry Andric bool hasLane() { return Lane != -1;} 431*0b57cec5SDimitry Andric bool hasReg() { return VGPR != 0;} 432*0b57cec5SDimitry Andric }; 433*0b57cec5SDimitry Andric 434*0b57cec5SDimitry Andric struct SGPRSpillVGPRCSR { 435*0b57cec5SDimitry Andric // VGPR used for SGPR spills 436*0b57cec5SDimitry Andric unsigned VGPR; 437*0b57cec5SDimitry Andric 438*0b57cec5SDimitry Andric // If the VGPR is a CSR, the stack slot used to save/restore it in the 439*0b57cec5SDimitry Andric // prolog/epilog. 440*0b57cec5SDimitry Andric Optional<int> FI; 441*0b57cec5SDimitry Andric 442*0b57cec5SDimitry Andric SGPRSpillVGPRCSR(unsigned V, Optional<int> F) : VGPR(V), FI(F) {} 443*0b57cec5SDimitry Andric }; 444*0b57cec5SDimitry Andric 445*0b57cec5SDimitry Andric struct VGPRSpillToAGPR { 446*0b57cec5SDimitry Andric SmallVector<MCPhysReg, 32> Lanes; 447*0b57cec5SDimitry Andric bool FullyAllocated = false; 448*0b57cec5SDimitry Andric }; 449*0b57cec5SDimitry Andric 450*0b57cec5SDimitry Andric SparseBitVector<> WWMReservedRegs; 451*0b57cec5SDimitry Andric 452*0b57cec5SDimitry Andric void ReserveWWMRegister(unsigned reg) { WWMReservedRegs.set(reg); } 453*0b57cec5SDimitry Andric 454*0b57cec5SDimitry Andric private: 455*0b57cec5SDimitry Andric // SGPR->VGPR spilling support. 456*0b57cec5SDimitry Andric using SpillRegMask = std::pair<unsigned, unsigned>; 457*0b57cec5SDimitry Andric 458*0b57cec5SDimitry Andric // Track VGPR + wave index for each subregister of the SGPR spilled to 459*0b57cec5SDimitry Andric // frameindex key. 460*0b57cec5SDimitry Andric DenseMap<int, std::vector<SpilledReg>> SGPRToVGPRSpills; 461*0b57cec5SDimitry Andric unsigned NumVGPRSpillLanes = 0; 462*0b57cec5SDimitry Andric SmallVector<SGPRSpillVGPRCSR, 2> SpillVGPRs; 463*0b57cec5SDimitry Andric 464*0b57cec5SDimitry Andric DenseMap<int, VGPRSpillToAGPR> VGPRToAGPRSpills; 465*0b57cec5SDimitry Andric 466*0b57cec5SDimitry Andric // AGPRs used for VGPR spills. 467*0b57cec5SDimitry Andric SmallVector<MCPhysReg, 32> SpillAGPR; 468*0b57cec5SDimitry Andric 469*0b57cec5SDimitry Andric // VGPRs used for AGPR spills. 470*0b57cec5SDimitry Andric SmallVector<MCPhysReg, 32> SpillVGPR; 471*0b57cec5SDimitry Andric 472*0b57cec5SDimitry Andric public: // FIXME 473*0b57cec5SDimitry Andric /// If this is set, an SGPR used for save/restore of the register used for the 474*0b57cec5SDimitry Andric /// frame pointer. 475*0b57cec5SDimitry Andric unsigned SGPRForFPSaveRestoreCopy = 0; 476*0b57cec5SDimitry Andric Optional<int> FramePointerSaveIndex; 477*0b57cec5SDimitry Andric 478*0b57cec5SDimitry Andric public: 479*0b57cec5SDimitry Andric SIMachineFunctionInfo(const MachineFunction &MF); 480*0b57cec5SDimitry Andric 481*0b57cec5SDimitry Andric bool initializeBaseYamlFields(const yaml::SIMachineFunctionInfo &YamlMFI); 482*0b57cec5SDimitry Andric 483*0b57cec5SDimitry Andric ArrayRef<SpilledReg> getSGPRToVGPRSpills(int FrameIndex) const { 484*0b57cec5SDimitry Andric auto I = SGPRToVGPRSpills.find(FrameIndex); 485*0b57cec5SDimitry Andric return (I == SGPRToVGPRSpills.end()) ? 486*0b57cec5SDimitry Andric ArrayRef<SpilledReg>() : makeArrayRef(I->second); 487*0b57cec5SDimitry Andric } 488*0b57cec5SDimitry Andric 489*0b57cec5SDimitry Andric ArrayRef<SGPRSpillVGPRCSR> getSGPRSpillVGPRs() const { 490*0b57cec5SDimitry Andric return SpillVGPRs; 491*0b57cec5SDimitry Andric } 492*0b57cec5SDimitry Andric 493*0b57cec5SDimitry Andric ArrayRef<MCPhysReg> getAGPRSpillVGPRs() const { 494*0b57cec5SDimitry Andric return SpillAGPR; 495*0b57cec5SDimitry Andric } 496*0b57cec5SDimitry Andric 497*0b57cec5SDimitry Andric ArrayRef<MCPhysReg> getVGPRSpillAGPRs() const { 498*0b57cec5SDimitry Andric return SpillVGPR; 499*0b57cec5SDimitry Andric } 500*0b57cec5SDimitry Andric 501*0b57cec5SDimitry Andric MCPhysReg getVGPRToAGPRSpill(int FrameIndex, unsigned Lane) const { 502*0b57cec5SDimitry Andric auto I = VGPRToAGPRSpills.find(FrameIndex); 503*0b57cec5SDimitry Andric return (I == VGPRToAGPRSpills.end()) ? (MCPhysReg)AMDGPU::NoRegister 504*0b57cec5SDimitry Andric : I->second.Lanes[Lane]; 505*0b57cec5SDimitry Andric } 506*0b57cec5SDimitry Andric 507*0b57cec5SDimitry Andric AMDGPU::SIModeRegisterDefaults getMode() const { 508*0b57cec5SDimitry Andric return Mode; 509*0b57cec5SDimitry Andric } 510*0b57cec5SDimitry Andric 511*0b57cec5SDimitry Andric bool haveFreeLanesForSGPRSpill(const MachineFunction &MF, 512*0b57cec5SDimitry Andric unsigned NumLane) const; 513*0b57cec5SDimitry Andric bool allocateSGPRSpillToVGPR(MachineFunction &MF, int FI); 514*0b57cec5SDimitry Andric bool allocateVGPRSpillToAGPR(MachineFunction &MF, int FI, bool isAGPRtoVGPR); 515*0b57cec5SDimitry Andric void removeDeadFrameIndices(MachineFrameInfo &MFI); 516*0b57cec5SDimitry Andric 517*0b57cec5SDimitry Andric bool hasCalculatedTID() const { return TIDReg != 0; }; 518*0b57cec5SDimitry Andric unsigned getTIDReg() const { return TIDReg; }; 519*0b57cec5SDimitry Andric void setTIDReg(unsigned Reg) { TIDReg = Reg; } 520*0b57cec5SDimitry Andric 521*0b57cec5SDimitry Andric unsigned getBytesInStackArgArea() const { 522*0b57cec5SDimitry Andric return BytesInStackArgArea; 523*0b57cec5SDimitry Andric } 524*0b57cec5SDimitry Andric 525*0b57cec5SDimitry Andric void setBytesInStackArgArea(unsigned Bytes) { 526*0b57cec5SDimitry Andric BytesInStackArgArea = Bytes; 527*0b57cec5SDimitry Andric } 528*0b57cec5SDimitry Andric 529*0b57cec5SDimitry Andric // Add user SGPRs. 530*0b57cec5SDimitry Andric unsigned addPrivateSegmentBuffer(const SIRegisterInfo &TRI); 531*0b57cec5SDimitry Andric unsigned addDispatchPtr(const SIRegisterInfo &TRI); 532*0b57cec5SDimitry Andric unsigned addQueuePtr(const SIRegisterInfo &TRI); 533*0b57cec5SDimitry Andric unsigned addKernargSegmentPtr(const SIRegisterInfo &TRI); 534*0b57cec5SDimitry Andric unsigned addDispatchID(const SIRegisterInfo &TRI); 535*0b57cec5SDimitry Andric unsigned addFlatScratchInit(const SIRegisterInfo &TRI); 536*0b57cec5SDimitry Andric unsigned addImplicitBufferPtr(const SIRegisterInfo &TRI); 537*0b57cec5SDimitry Andric 538*0b57cec5SDimitry Andric // Add system SGPRs. 539*0b57cec5SDimitry Andric unsigned addWorkGroupIDX() { 540*0b57cec5SDimitry Andric ArgInfo.WorkGroupIDX = ArgDescriptor::createRegister(getNextSystemSGPR()); 541*0b57cec5SDimitry Andric NumSystemSGPRs += 1; 542*0b57cec5SDimitry Andric return ArgInfo.WorkGroupIDX.getRegister(); 543*0b57cec5SDimitry Andric } 544*0b57cec5SDimitry Andric 545*0b57cec5SDimitry Andric unsigned addWorkGroupIDY() { 546*0b57cec5SDimitry Andric ArgInfo.WorkGroupIDY = ArgDescriptor::createRegister(getNextSystemSGPR()); 547*0b57cec5SDimitry Andric NumSystemSGPRs += 1; 548*0b57cec5SDimitry Andric return ArgInfo.WorkGroupIDY.getRegister(); 549*0b57cec5SDimitry Andric } 550*0b57cec5SDimitry Andric 551*0b57cec5SDimitry Andric unsigned addWorkGroupIDZ() { 552*0b57cec5SDimitry Andric ArgInfo.WorkGroupIDZ = ArgDescriptor::createRegister(getNextSystemSGPR()); 553*0b57cec5SDimitry Andric NumSystemSGPRs += 1; 554*0b57cec5SDimitry Andric return ArgInfo.WorkGroupIDZ.getRegister(); 555*0b57cec5SDimitry Andric } 556*0b57cec5SDimitry Andric 557*0b57cec5SDimitry Andric unsigned addWorkGroupInfo() { 558*0b57cec5SDimitry Andric ArgInfo.WorkGroupInfo = ArgDescriptor::createRegister(getNextSystemSGPR()); 559*0b57cec5SDimitry Andric NumSystemSGPRs += 1; 560*0b57cec5SDimitry Andric return ArgInfo.WorkGroupInfo.getRegister(); 561*0b57cec5SDimitry Andric } 562*0b57cec5SDimitry Andric 563*0b57cec5SDimitry Andric // Add special VGPR inputs 564*0b57cec5SDimitry Andric void setWorkItemIDX(ArgDescriptor Arg) { 565*0b57cec5SDimitry Andric ArgInfo.WorkItemIDX = Arg; 566*0b57cec5SDimitry Andric } 567*0b57cec5SDimitry Andric 568*0b57cec5SDimitry Andric void setWorkItemIDY(ArgDescriptor Arg) { 569*0b57cec5SDimitry Andric ArgInfo.WorkItemIDY = Arg; 570*0b57cec5SDimitry Andric } 571*0b57cec5SDimitry Andric 572*0b57cec5SDimitry Andric void setWorkItemIDZ(ArgDescriptor Arg) { 573*0b57cec5SDimitry Andric ArgInfo.WorkItemIDZ = Arg; 574*0b57cec5SDimitry Andric } 575*0b57cec5SDimitry Andric 576*0b57cec5SDimitry Andric unsigned addPrivateSegmentWaveByteOffset() { 577*0b57cec5SDimitry Andric ArgInfo.PrivateSegmentWaveByteOffset 578*0b57cec5SDimitry Andric = ArgDescriptor::createRegister(getNextSystemSGPR()); 579*0b57cec5SDimitry Andric NumSystemSGPRs += 1; 580*0b57cec5SDimitry Andric return ArgInfo.PrivateSegmentWaveByteOffset.getRegister(); 581*0b57cec5SDimitry Andric } 582*0b57cec5SDimitry Andric 583*0b57cec5SDimitry Andric void setPrivateSegmentWaveByteOffset(unsigned Reg) { 584*0b57cec5SDimitry Andric ArgInfo.PrivateSegmentWaveByteOffset = ArgDescriptor::createRegister(Reg); 585*0b57cec5SDimitry Andric } 586*0b57cec5SDimitry Andric 587*0b57cec5SDimitry Andric bool hasPrivateSegmentBuffer() const { 588*0b57cec5SDimitry Andric return PrivateSegmentBuffer; 589*0b57cec5SDimitry Andric } 590*0b57cec5SDimitry Andric 591*0b57cec5SDimitry Andric bool hasDispatchPtr() const { 592*0b57cec5SDimitry Andric return DispatchPtr; 593*0b57cec5SDimitry Andric } 594*0b57cec5SDimitry Andric 595*0b57cec5SDimitry Andric bool hasQueuePtr() const { 596*0b57cec5SDimitry Andric return QueuePtr; 597*0b57cec5SDimitry Andric } 598*0b57cec5SDimitry Andric 599*0b57cec5SDimitry Andric bool hasKernargSegmentPtr() const { 600*0b57cec5SDimitry Andric return KernargSegmentPtr; 601*0b57cec5SDimitry Andric } 602*0b57cec5SDimitry Andric 603*0b57cec5SDimitry Andric bool hasDispatchID() const { 604*0b57cec5SDimitry Andric return DispatchID; 605*0b57cec5SDimitry Andric } 606*0b57cec5SDimitry Andric 607*0b57cec5SDimitry Andric bool hasFlatScratchInit() const { 608*0b57cec5SDimitry Andric return FlatScratchInit; 609*0b57cec5SDimitry Andric } 610*0b57cec5SDimitry Andric 611*0b57cec5SDimitry Andric bool hasWorkGroupIDX() const { 612*0b57cec5SDimitry Andric return WorkGroupIDX; 613*0b57cec5SDimitry Andric } 614*0b57cec5SDimitry Andric 615*0b57cec5SDimitry Andric bool hasWorkGroupIDY() const { 616*0b57cec5SDimitry Andric return WorkGroupIDY; 617*0b57cec5SDimitry Andric } 618*0b57cec5SDimitry Andric 619*0b57cec5SDimitry Andric bool hasWorkGroupIDZ() const { 620*0b57cec5SDimitry Andric return WorkGroupIDZ; 621*0b57cec5SDimitry Andric } 622*0b57cec5SDimitry Andric 623*0b57cec5SDimitry Andric bool hasWorkGroupInfo() const { 624*0b57cec5SDimitry Andric return WorkGroupInfo; 625*0b57cec5SDimitry Andric } 626*0b57cec5SDimitry Andric 627*0b57cec5SDimitry Andric bool hasPrivateSegmentWaveByteOffset() const { 628*0b57cec5SDimitry Andric return PrivateSegmentWaveByteOffset; 629*0b57cec5SDimitry Andric } 630*0b57cec5SDimitry Andric 631*0b57cec5SDimitry Andric bool hasWorkItemIDX() const { 632*0b57cec5SDimitry Andric return WorkItemIDX; 633*0b57cec5SDimitry Andric } 634*0b57cec5SDimitry Andric 635*0b57cec5SDimitry Andric bool hasWorkItemIDY() const { 636*0b57cec5SDimitry Andric return WorkItemIDY; 637*0b57cec5SDimitry Andric } 638*0b57cec5SDimitry Andric 639*0b57cec5SDimitry Andric bool hasWorkItemIDZ() const { 640*0b57cec5SDimitry Andric return WorkItemIDZ; 641*0b57cec5SDimitry Andric } 642*0b57cec5SDimitry Andric 643*0b57cec5SDimitry Andric bool hasImplicitArgPtr() const { 644*0b57cec5SDimitry Andric return ImplicitArgPtr; 645*0b57cec5SDimitry Andric } 646*0b57cec5SDimitry Andric 647*0b57cec5SDimitry Andric bool hasImplicitBufferPtr() const { 648*0b57cec5SDimitry Andric return ImplicitBufferPtr; 649*0b57cec5SDimitry Andric } 650*0b57cec5SDimitry Andric 651*0b57cec5SDimitry Andric AMDGPUFunctionArgInfo &getArgInfo() { 652*0b57cec5SDimitry Andric return ArgInfo; 653*0b57cec5SDimitry Andric } 654*0b57cec5SDimitry Andric 655*0b57cec5SDimitry Andric const AMDGPUFunctionArgInfo &getArgInfo() const { 656*0b57cec5SDimitry Andric return ArgInfo; 657*0b57cec5SDimitry Andric } 658*0b57cec5SDimitry Andric 659*0b57cec5SDimitry Andric std::pair<const ArgDescriptor *, const TargetRegisterClass *> 660*0b57cec5SDimitry Andric getPreloadedValue(AMDGPUFunctionArgInfo::PreloadedValue Value) const { 661*0b57cec5SDimitry Andric return ArgInfo.getPreloadedValue(Value); 662*0b57cec5SDimitry Andric } 663*0b57cec5SDimitry Andric 664*0b57cec5SDimitry Andric Register getPreloadedReg(AMDGPUFunctionArgInfo::PreloadedValue Value) const { 665*0b57cec5SDimitry Andric auto Arg = ArgInfo.getPreloadedValue(Value).first; 666*0b57cec5SDimitry Andric return Arg ? Arg->getRegister() : Register(); 667*0b57cec5SDimitry Andric } 668*0b57cec5SDimitry Andric 669*0b57cec5SDimitry Andric unsigned getGITPtrHigh() const { 670*0b57cec5SDimitry Andric return GITPtrHigh; 671*0b57cec5SDimitry Andric } 672*0b57cec5SDimitry Andric 673*0b57cec5SDimitry Andric unsigned get32BitAddressHighBits() const { 674*0b57cec5SDimitry Andric return HighBitsOf32BitAddress; 675*0b57cec5SDimitry Andric } 676*0b57cec5SDimitry Andric 677*0b57cec5SDimitry Andric unsigned getGDSSize() const { 678*0b57cec5SDimitry Andric return GDSSize; 679*0b57cec5SDimitry Andric } 680*0b57cec5SDimitry Andric 681*0b57cec5SDimitry Andric unsigned getNumUserSGPRs() const { 682*0b57cec5SDimitry Andric return NumUserSGPRs; 683*0b57cec5SDimitry Andric } 684*0b57cec5SDimitry Andric 685*0b57cec5SDimitry Andric unsigned getNumPreloadedSGPRs() const { 686*0b57cec5SDimitry Andric return NumUserSGPRs + NumSystemSGPRs; 687*0b57cec5SDimitry Andric } 688*0b57cec5SDimitry Andric 689*0b57cec5SDimitry Andric unsigned getPrivateSegmentWaveByteOffsetSystemSGPR() const { 690*0b57cec5SDimitry Andric return ArgInfo.PrivateSegmentWaveByteOffset.getRegister(); 691*0b57cec5SDimitry Andric } 692*0b57cec5SDimitry Andric 693*0b57cec5SDimitry Andric /// Returns the physical register reserved for use as the resource 694*0b57cec5SDimitry Andric /// descriptor for scratch accesses. 695*0b57cec5SDimitry Andric unsigned getScratchRSrcReg() const { 696*0b57cec5SDimitry Andric return ScratchRSrcReg; 697*0b57cec5SDimitry Andric } 698*0b57cec5SDimitry Andric 699*0b57cec5SDimitry Andric void setScratchRSrcReg(unsigned Reg) { 700*0b57cec5SDimitry Andric assert(Reg != 0 && "Should never be unset"); 701*0b57cec5SDimitry Andric ScratchRSrcReg = Reg; 702*0b57cec5SDimitry Andric } 703*0b57cec5SDimitry Andric 704*0b57cec5SDimitry Andric unsigned getScratchWaveOffsetReg() const { 705*0b57cec5SDimitry Andric return ScratchWaveOffsetReg; 706*0b57cec5SDimitry Andric } 707*0b57cec5SDimitry Andric 708*0b57cec5SDimitry Andric unsigned getFrameOffsetReg() const { 709*0b57cec5SDimitry Andric return FrameOffsetReg; 710*0b57cec5SDimitry Andric } 711*0b57cec5SDimitry Andric 712*0b57cec5SDimitry Andric void setFrameOffsetReg(unsigned Reg) { 713*0b57cec5SDimitry Andric assert(Reg != 0 && "Should never be unset"); 714*0b57cec5SDimitry Andric FrameOffsetReg = Reg; 715*0b57cec5SDimitry Andric } 716*0b57cec5SDimitry Andric 717*0b57cec5SDimitry Andric void setStackPtrOffsetReg(unsigned Reg) { 718*0b57cec5SDimitry Andric assert(Reg != 0 && "Should never be unset"); 719*0b57cec5SDimitry Andric StackPtrOffsetReg = Reg; 720*0b57cec5SDimitry Andric } 721*0b57cec5SDimitry Andric 722*0b57cec5SDimitry Andric // Note the unset value for this is AMDGPU::SP_REG rather than 723*0b57cec5SDimitry Andric // NoRegister. This is mostly a workaround for MIR tests where state that 724*0b57cec5SDimitry Andric // can't be directly computed from the function is not preserved in serialized 725*0b57cec5SDimitry Andric // MIR. 726*0b57cec5SDimitry Andric unsigned getStackPtrOffsetReg() const { 727*0b57cec5SDimitry Andric return StackPtrOffsetReg; 728*0b57cec5SDimitry Andric } 729*0b57cec5SDimitry Andric 730*0b57cec5SDimitry Andric void setScratchWaveOffsetReg(unsigned Reg) { 731*0b57cec5SDimitry Andric assert(Reg != 0 && "Should never be unset"); 732*0b57cec5SDimitry Andric ScratchWaveOffsetReg = Reg; 733*0b57cec5SDimitry Andric } 734*0b57cec5SDimitry Andric 735*0b57cec5SDimitry Andric unsigned getQueuePtrUserSGPR() const { 736*0b57cec5SDimitry Andric return ArgInfo.QueuePtr.getRegister(); 737*0b57cec5SDimitry Andric } 738*0b57cec5SDimitry Andric 739*0b57cec5SDimitry Andric unsigned getImplicitBufferPtrUserSGPR() const { 740*0b57cec5SDimitry Andric return ArgInfo.ImplicitBufferPtr.getRegister(); 741*0b57cec5SDimitry Andric } 742*0b57cec5SDimitry Andric 743*0b57cec5SDimitry Andric bool hasSpilledSGPRs() const { 744*0b57cec5SDimitry Andric return HasSpilledSGPRs; 745*0b57cec5SDimitry Andric } 746*0b57cec5SDimitry Andric 747*0b57cec5SDimitry Andric void setHasSpilledSGPRs(bool Spill = true) { 748*0b57cec5SDimitry Andric HasSpilledSGPRs = Spill; 749*0b57cec5SDimitry Andric } 750*0b57cec5SDimitry Andric 751*0b57cec5SDimitry Andric bool hasSpilledVGPRs() const { 752*0b57cec5SDimitry Andric return HasSpilledVGPRs; 753*0b57cec5SDimitry Andric } 754*0b57cec5SDimitry Andric 755*0b57cec5SDimitry Andric void setHasSpilledVGPRs(bool Spill = true) { 756*0b57cec5SDimitry Andric HasSpilledVGPRs = Spill; 757*0b57cec5SDimitry Andric } 758*0b57cec5SDimitry Andric 759*0b57cec5SDimitry Andric bool hasNonSpillStackObjects() const { 760*0b57cec5SDimitry Andric return HasNonSpillStackObjects; 761*0b57cec5SDimitry Andric } 762*0b57cec5SDimitry Andric 763*0b57cec5SDimitry Andric void setHasNonSpillStackObjects(bool StackObject = true) { 764*0b57cec5SDimitry Andric HasNonSpillStackObjects = StackObject; 765*0b57cec5SDimitry Andric } 766*0b57cec5SDimitry Andric 767*0b57cec5SDimitry Andric bool isStackRealigned() const { 768*0b57cec5SDimitry Andric return IsStackRealigned; 769*0b57cec5SDimitry Andric } 770*0b57cec5SDimitry Andric 771*0b57cec5SDimitry Andric void setIsStackRealigned(bool Realigned = true) { 772*0b57cec5SDimitry Andric IsStackRealigned = Realigned; 773*0b57cec5SDimitry Andric } 774*0b57cec5SDimitry Andric 775*0b57cec5SDimitry Andric unsigned getNumSpilledSGPRs() const { 776*0b57cec5SDimitry Andric return NumSpilledSGPRs; 777*0b57cec5SDimitry Andric } 778*0b57cec5SDimitry Andric 779*0b57cec5SDimitry Andric unsigned getNumSpilledVGPRs() const { 780*0b57cec5SDimitry Andric return NumSpilledVGPRs; 781*0b57cec5SDimitry Andric } 782*0b57cec5SDimitry Andric 783*0b57cec5SDimitry Andric void addToSpilledSGPRs(unsigned num) { 784*0b57cec5SDimitry Andric NumSpilledSGPRs += num; 785*0b57cec5SDimitry Andric } 786*0b57cec5SDimitry Andric 787*0b57cec5SDimitry Andric void addToSpilledVGPRs(unsigned num) { 788*0b57cec5SDimitry Andric NumSpilledVGPRs += num; 789*0b57cec5SDimitry Andric } 790*0b57cec5SDimitry Andric 791*0b57cec5SDimitry Andric unsigned getPSInputAddr() const { 792*0b57cec5SDimitry Andric return PSInputAddr; 793*0b57cec5SDimitry Andric } 794*0b57cec5SDimitry Andric 795*0b57cec5SDimitry Andric unsigned getPSInputEnable() const { 796*0b57cec5SDimitry Andric return PSInputEnable; 797*0b57cec5SDimitry Andric } 798*0b57cec5SDimitry Andric 799*0b57cec5SDimitry Andric bool isPSInputAllocated(unsigned Index) const { 800*0b57cec5SDimitry Andric return PSInputAddr & (1 << Index); 801*0b57cec5SDimitry Andric } 802*0b57cec5SDimitry Andric 803*0b57cec5SDimitry Andric void markPSInputAllocated(unsigned Index) { 804*0b57cec5SDimitry Andric PSInputAddr |= 1 << Index; 805*0b57cec5SDimitry Andric } 806*0b57cec5SDimitry Andric 807*0b57cec5SDimitry Andric void markPSInputEnabled(unsigned Index) { 808*0b57cec5SDimitry Andric PSInputEnable |= 1 << Index; 809*0b57cec5SDimitry Andric } 810*0b57cec5SDimitry Andric 811*0b57cec5SDimitry Andric bool returnsVoid() const { 812*0b57cec5SDimitry Andric return ReturnsVoid; 813*0b57cec5SDimitry Andric } 814*0b57cec5SDimitry Andric 815*0b57cec5SDimitry Andric void setIfReturnsVoid(bool Value) { 816*0b57cec5SDimitry Andric ReturnsVoid = Value; 817*0b57cec5SDimitry Andric } 818*0b57cec5SDimitry Andric 819*0b57cec5SDimitry Andric /// \returns A pair of default/requested minimum/maximum flat work group sizes 820*0b57cec5SDimitry Andric /// for this function. 821*0b57cec5SDimitry Andric std::pair<unsigned, unsigned> getFlatWorkGroupSizes() const { 822*0b57cec5SDimitry Andric return FlatWorkGroupSizes; 823*0b57cec5SDimitry Andric } 824*0b57cec5SDimitry Andric 825*0b57cec5SDimitry Andric /// \returns Default/requested minimum flat work group size for this function. 826*0b57cec5SDimitry Andric unsigned getMinFlatWorkGroupSize() const { 827*0b57cec5SDimitry Andric return FlatWorkGroupSizes.first; 828*0b57cec5SDimitry Andric } 829*0b57cec5SDimitry Andric 830*0b57cec5SDimitry Andric /// \returns Default/requested maximum flat work group size for this function. 831*0b57cec5SDimitry Andric unsigned getMaxFlatWorkGroupSize() const { 832*0b57cec5SDimitry Andric return FlatWorkGroupSizes.second; 833*0b57cec5SDimitry Andric } 834*0b57cec5SDimitry Andric 835*0b57cec5SDimitry Andric /// \returns A pair of default/requested minimum/maximum number of waves per 836*0b57cec5SDimitry Andric /// execution unit. 837*0b57cec5SDimitry Andric std::pair<unsigned, unsigned> getWavesPerEU() const { 838*0b57cec5SDimitry Andric return WavesPerEU; 839*0b57cec5SDimitry Andric } 840*0b57cec5SDimitry Andric 841*0b57cec5SDimitry Andric /// \returns Default/requested minimum number of waves per execution unit. 842*0b57cec5SDimitry Andric unsigned getMinWavesPerEU() const { 843*0b57cec5SDimitry Andric return WavesPerEU.first; 844*0b57cec5SDimitry Andric } 845*0b57cec5SDimitry Andric 846*0b57cec5SDimitry Andric /// \returns Default/requested maximum number of waves per execution unit. 847*0b57cec5SDimitry Andric unsigned getMaxWavesPerEU() const { 848*0b57cec5SDimitry Andric return WavesPerEU.second; 849*0b57cec5SDimitry Andric } 850*0b57cec5SDimitry Andric 851*0b57cec5SDimitry Andric /// \returns SGPR used for \p Dim's work group ID. 852*0b57cec5SDimitry Andric unsigned getWorkGroupIDSGPR(unsigned Dim) const { 853*0b57cec5SDimitry Andric switch (Dim) { 854*0b57cec5SDimitry Andric case 0: 855*0b57cec5SDimitry Andric assert(hasWorkGroupIDX()); 856*0b57cec5SDimitry Andric return ArgInfo.WorkGroupIDX.getRegister(); 857*0b57cec5SDimitry Andric case 1: 858*0b57cec5SDimitry Andric assert(hasWorkGroupIDY()); 859*0b57cec5SDimitry Andric return ArgInfo.WorkGroupIDY.getRegister(); 860*0b57cec5SDimitry Andric case 2: 861*0b57cec5SDimitry Andric assert(hasWorkGroupIDZ()); 862*0b57cec5SDimitry Andric return ArgInfo.WorkGroupIDZ.getRegister(); 863*0b57cec5SDimitry Andric } 864*0b57cec5SDimitry Andric llvm_unreachable("unexpected dimension"); 865*0b57cec5SDimitry Andric } 866*0b57cec5SDimitry Andric 867*0b57cec5SDimitry Andric unsigned getLDSWaveSpillSize() const { 868*0b57cec5SDimitry Andric return LDSWaveSpillSize; 869*0b57cec5SDimitry Andric } 870*0b57cec5SDimitry Andric 871*0b57cec5SDimitry Andric const AMDGPUBufferPseudoSourceValue *getBufferPSV(const SIInstrInfo &TII, 872*0b57cec5SDimitry Andric const Value *BufferRsrc) { 873*0b57cec5SDimitry Andric assert(BufferRsrc); 874*0b57cec5SDimitry Andric auto PSV = BufferPSVs.try_emplace( 875*0b57cec5SDimitry Andric BufferRsrc, 876*0b57cec5SDimitry Andric llvm::make_unique<AMDGPUBufferPseudoSourceValue>(TII)); 877*0b57cec5SDimitry Andric return PSV.first->second.get(); 878*0b57cec5SDimitry Andric } 879*0b57cec5SDimitry Andric 880*0b57cec5SDimitry Andric const AMDGPUImagePseudoSourceValue *getImagePSV(const SIInstrInfo &TII, 881*0b57cec5SDimitry Andric const Value *ImgRsrc) { 882*0b57cec5SDimitry Andric assert(ImgRsrc); 883*0b57cec5SDimitry Andric auto PSV = ImagePSVs.try_emplace( 884*0b57cec5SDimitry Andric ImgRsrc, 885*0b57cec5SDimitry Andric llvm::make_unique<AMDGPUImagePseudoSourceValue>(TII)); 886*0b57cec5SDimitry Andric return PSV.first->second.get(); 887*0b57cec5SDimitry Andric } 888*0b57cec5SDimitry Andric 889*0b57cec5SDimitry Andric const AMDGPUGWSResourcePseudoSourceValue *getGWSPSV(const SIInstrInfo &TII) { 890*0b57cec5SDimitry Andric if (!GWSResourcePSV) { 891*0b57cec5SDimitry Andric GWSResourcePSV = 892*0b57cec5SDimitry Andric llvm::make_unique<AMDGPUGWSResourcePseudoSourceValue>(TII); 893*0b57cec5SDimitry Andric } 894*0b57cec5SDimitry Andric 895*0b57cec5SDimitry Andric return GWSResourcePSV.get(); 896*0b57cec5SDimitry Andric } 897*0b57cec5SDimitry Andric 898*0b57cec5SDimitry Andric unsigned getOccupancy() const { 899*0b57cec5SDimitry Andric return Occupancy; 900*0b57cec5SDimitry Andric } 901*0b57cec5SDimitry Andric 902*0b57cec5SDimitry Andric unsigned getMinAllowedOccupancy() const { 903*0b57cec5SDimitry Andric if (!isMemoryBound() && !needsWaveLimiter()) 904*0b57cec5SDimitry Andric return Occupancy; 905*0b57cec5SDimitry Andric return (Occupancy < 4) ? Occupancy : 4; 906*0b57cec5SDimitry Andric } 907*0b57cec5SDimitry Andric 908*0b57cec5SDimitry Andric void limitOccupancy(const MachineFunction &MF); 909*0b57cec5SDimitry Andric 910*0b57cec5SDimitry Andric void limitOccupancy(unsigned Limit) { 911*0b57cec5SDimitry Andric if (Occupancy > Limit) 912*0b57cec5SDimitry Andric Occupancy = Limit; 913*0b57cec5SDimitry Andric } 914*0b57cec5SDimitry Andric 915*0b57cec5SDimitry Andric void increaseOccupancy(const MachineFunction &MF, unsigned Limit) { 916*0b57cec5SDimitry Andric if (Occupancy < Limit) 917*0b57cec5SDimitry Andric Occupancy = Limit; 918*0b57cec5SDimitry Andric limitOccupancy(MF); 919*0b57cec5SDimitry Andric } 920*0b57cec5SDimitry Andric }; 921*0b57cec5SDimitry Andric 922*0b57cec5SDimitry Andric } // end namespace llvm 923*0b57cec5SDimitry Andric 924*0b57cec5SDimitry Andric #endif // LLVM_LIB_TARGET_AMDGPU_SIMACHINEFUNCTIONINFO_H 925