18f0fd8f6SDimitry Andric //===-- AMDGPUAsmPrinter.cpp - AMDGPU Assebly printer --------------------===// 28f0fd8f6SDimitry Andric // 38f0fd8f6SDimitry Andric // The LLVM Compiler Infrastructure 48f0fd8f6SDimitry Andric // 58f0fd8f6SDimitry Andric // This file is distributed under the University of Illinois Open Source 68f0fd8f6SDimitry Andric // License. See LICENSE.TXT for details. 78f0fd8f6SDimitry Andric // 88f0fd8f6SDimitry Andric //===----------------------------------------------------------------------===// 98f0fd8f6SDimitry Andric // 108f0fd8f6SDimitry Andric /// \file 118f0fd8f6SDimitry Andric /// 128f0fd8f6SDimitry Andric /// The AMDGPUAsmPrinter is used to print both assembly string and also binary 138f0fd8f6SDimitry Andric /// code. When passed an MCAsmStreamer it prints assembly and when passed 148f0fd8f6SDimitry Andric /// an MCObjectStreamer it outputs binary code. 158f0fd8f6SDimitry Andric // 168f0fd8f6SDimitry Andric //===----------------------------------------------------------------------===// 178f0fd8f6SDimitry Andric // 188f0fd8f6SDimitry Andric 198f0fd8f6SDimitry Andric #include "AMDGPUAsmPrinter.h" 208f0fd8f6SDimitry Andric #include "AMDGPU.h" 218f0fd8f6SDimitry Andric #include "AMDGPUSubtarget.h" 22db17bf38SDimitry Andric #include "AMDGPUTargetMachine.h" 23db17bf38SDimitry Andric #include "InstPrinter/AMDGPUInstPrinter.h" 24db17bf38SDimitry Andric #include "MCTargetDesc/AMDGPUTargetStreamer.h" 258f0fd8f6SDimitry Andric #include "R600Defines.h" 268f0fd8f6SDimitry Andric #include "R600MachineFunctionInfo.h" 278f0fd8f6SDimitry Andric #include "R600RegisterInfo.h" 288f0fd8f6SDimitry Andric #include "SIDefines.h" 293ca95b02SDimitry Andric #include "SIInstrInfo.h" 30db17bf38SDimitry Andric #include "SIMachineFunctionInfo.h" 318f0fd8f6SDimitry Andric #include "SIRegisterInfo.h" 32db17bf38SDimitry Andric #include "Utils/AMDGPUBaseInfo.h" 33db17bf38SDimitry Andric #include "llvm/BinaryFormat/ELF.h" 348f0fd8f6SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 352cab237bSDimitry Andric #include "llvm/CodeGen/TargetLoweringObjectFile.h" 363ca95b02SDimitry Andric #include "llvm/IR/DiagnosticInfo.h" 378f0fd8f6SDimitry Andric #include "llvm/MC/MCContext.h" 388f0fd8f6SDimitry Andric #include "llvm/MC/MCSectionELF.h" 398f0fd8f6SDimitry Andric #include "llvm/MC/MCStreamer.h" 402cab237bSDimitry Andric #include "llvm/Support/AMDGPUMetadata.h" 418f0fd8f6SDimitry Andric #include "llvm/Support/MathExtras.h" 428f0fd8f6SDimitry Andric #include "llvm/Support/TargetRegistry.h" 438f0fd8f6SDimitry Andric 448f0fd8f6SDimitry Andric using namespace llvm; 452cab237bSDimitry Andric using namespace llvm::AMDGPU; 468f0fd8f6SDimitry Andric 478f0fd8f6SDimitry Andric // TODO: This should get the default rounding mode from the kernel. We just set 488f0fd8f6SDimitry Andric // the default here, but this could change if the OpenCL rounding mode pragmas 498f0fd8f6SDimitry Andric // are used. 508f0fd8f6SDimitry Andric // 518f0fd8f6SDimitry Andric // The denormal mode here should match what is reported by the OpenCL runtime 528f0fd8f6SDimitry Andric // for the CL_FP_DENORM bit from CL_DEVICE_{HALF|SINGLE|DOUBLE}_FP_CONFIG, but 538f0fd8f6SDimitry Andric // can also be override to flush with the -cl-denorms-are-zero compiler flag. 548f0fd8f6SDimitry Andric // 558f0fd8f6SDimitry Andric // AMD OpenCL only sets flush none and reports CL_FP_DENORM for double 568f0fd8f6SDimitry Andric // precision, and leaves single precision to flush all and does not report 578f0fd8f6SDimitry Andric // CL_FP_DENORM for CL_DEVICE_SINGLE_FP_CONFIG. Mesa's OpenCL currently reports 588f0fd8f6SDimitry Andric // CL_FP_DENORM for both. 598f0fd8f6SDimitry Andric // 608f0fd8f6SDimitry Andric // FIXME: It seems some instructions do not support single precision denormals 618f0fd8f6SDimitry Andric // regardless of the mode (exp_*_f32, rcp_*_f32, rsq_*_f32, rsq_*f32, sqrt_f32, 628f0fd8f6SDimitry Andric // and sin_f32, cos_f32 on most parts). 638f0fd8f6SDimitry Andric 648f0fd8f6SDimitry Andric // We want to use these instructions, and using fp32 denormals also causes 658f0fd8f6SDimitry Andric // instructions to run at the double precision rate for the device so it's 668f0fd8f6SDimitry Andric // probably best to just report no single precision denormals. 678f0fd8f6SDimitry Andric static uint32_t getFPMode(const MachineFunction &F) { 683ca95b02SDimitry Andric const SISubtarget& ST = F.getSubtarget<SISubtarget>(); 698f0fd8f6SDimitry Andric // TODO: Is there any real use for the flush in only / flush out only modes? 708f0fd8f6SDimitry Andric 718f0fd8f6SDimitry Andric uint32_t FP32Denormals = 728f0fd8f6SDimitry Andric ST.hasFP32Denormals() ? FP_DENORM_FLUSH_NONE : FP_DENORM_FLUSH_IN_FLUSH_OUT; 738f0fd8f6SDimitry Andric 748f0fd8f6SDimitry Andric uint32_t FP64Denormals = 758f0fd8f6SDimitry Andric ST.hasFP64Denormals() ? FP_DENORM_FLUSH_NONE : FP_DENORM_FLUSH_IN_FLUSH_OUT; 768f0fd8f6SDimitry Andric 778f0fd8f6SDimitry Andric return FP_ROUND_MODE_SP(FP_ROUND_ROUND_TO_NEAREST) | 788f0fd8f6SDimitry Andric FP_ROUND_MODE_DP(FP_ROUND_ROUND_TO_NEAREST) | 798f0fd8f6SDimitry Andric FP_DENORM_MODE_SP(FP32Denormals) | 808f0fd8f6SDimitry Andric FP_DENORM_MODE_DP(FP64Denormals); 818f0fd8f6SDimitry Andric } 828f0fd8f6SDimitry Andric 838f0fd8f6SDimitry Andric static AsmPrinter * 848f0fd8f6SDimitry Andric createAMDGPUAsmPrinterPass(TargetMachine &tm, 858f0fd8f6SDimitry Andric std::unique_ptr<MCStreamer> &&Streamer) { 868f0fd8f6SDimitry Andric return new AMDGPUAsmPrinter(tm, std::move(Streamer)); 878f0fd8f6SDimitry Andric } 888f0fd8f6SDimitry Andric 898f0fd8f6SDimitry Andric extern "C" void LLVMInitializeAMDGPUAsmPrinter() { 90d88c1a5aSDimitry Andric TargetRegistry::RegisterAsmPrinter(getTheAMDGPUTarget(), 91d88c1a5aSDimitry Andric createAMDGPUAsmPrinterPass); 92d88c1a5aSDimitry Andric TargetRegistry::RegisterAsmPrinter(getTheGCNTarget(), 93d88c1a5aSDimitry Andric createAMDGPUAsmPrinterPass); 948f0fd8f6SDimitry Andric } 958f0fd8f6SDimitry Andric 968f0fd8f6SDimitry Andric AMDGPUAsmPrinter::AMDGPUAsmPrinter(TargetMachine &TM, 978f0fd8f6SDimitry Andric std::unique_ptr<MCStreamer> Streamer) 987a7e6055SDimitry Andric : AsmPrinter(TM, std::move(Streamer)) { 997a7e6055SDimitry Andric AMDGPUASI = static_cast<AMDGPUTargetMachine*>(&TM)->getAMDGPUAS(); 1007a7e6055SDimitry Andric } 1018f0fd8f6SDimitry Andric 102d88c1a5aSDimitry Andric StringRef AMDGPUAsmPrinter::getPassName() const { 103d88c1a5aSDimitry Andric return "AMDGPU Assembly Printer"; 104d88c1a5aSDimitry Andric } 105d88c1a5aSDimitry Andric 1067a7e6055SDimitry Andric const MCSubtargetInfo* AMDGPUAsmPrinter::getSTI() const { 1077a7e6055SDimitry Andric return TM.getMCSubtargetInfo(); 1087a7e6055SDimitry Andric } 1097a7e6055SDimitry Andric 1102cab237bSDimitry Andric AMDGPUTargetStreamer* AMDGPUAsmPrinter::getTargetStreamer() const { 1112cab237bSDimitry Andric if (!OutStreamer) 1122cab237bSDimitry Andric return nullptr; 1132cab237bSDimitry Andric return static_cast<AMDGPUTargetStreamer*>(OutStreamer->getTargetStreamer()); 1147a7e6055SDimitry Andric } 1157a7e6055SDimitry Andric 116444ed5c5SDimitry Andric void AMDGPUAsmPrinter::EmitStartOfAsmFile(Module &M) { 1172cab237bSDimitry Andric if (TM.getTargetTriple().getArch() != Triple::amdgcn) 118444ed5c5SDimitry Andric return; 119444ed5c5SDimitry Andric 1202cab237bSDimitry Andric if (TM.getTargetTriple().getOS() != Triple::AMDHSA && 1212cab237bSDimitry Andric TM.getTargetTriple().getOS() != Triple::AMDPAL) 1222cab237bSDimitry Andric return; 123444ed5c5SDimitry Andric 1242cab237bSDimitry Andric if (TM.getTargetTriple().getOS() == Triple::AMDHSA) 1252cab237bSDimitry Andric HSAMetadataStream.begin(M); 1262cab237bSDimitry Andric 1272cab237bSDimitry Andric if (TM.getTargetTriple().getOS() == Triple::AMDPAL) 1282cab237bSDimitry Andric readPALMetadata(M); 1292cab237bSDimitry Andric 1302cab237bSDimitry Andric // Deprecated notes are not emitted for code object v3. 1312cab237bSDimitry Andric if (IsaInfo::hasCodeObjectV3(getSTI()->getFeatureBits())) 1322cab237bSDimitry Andric return; 1332cab237bSDimitry Andric 1342cab237bSDimitry Andric // HSA emits NT_AMDGPU_HSA_CODE_OBJECT_VERSION for code objects v2. 1352cab237bSDimitry Andric if (TM.getTargetTriple().getOS() == Triple::AMDHSA) 1362cab237bSDimitry Andric getTargetStreamer()->EmitDirectiveHSACodeObjectVersion(2, 1); 1372cab237bSDimitry Andric 1382cab237bSDimitry Andric // HSA and PAL emit NT_AMDGPU_HSA_ISA for code objects v2. 1392cab237bSDimitry Andric IsaInfo::IsaVersion ISA = IsaInfo::getIsaVersion(getSTI()->getFeatureBits()); 1402cab237bSDimitry Andric getTargetStreamer()->EmitDirectiveHSACodeObjectISA( 1417a7e6055SDimitry Andric ISA.Major, ISA.Minor, ISA.Stepping, "AMD", "AMDGPU"); 1427a7e6055SDimitry Andric } 143444ed5c5SDimitry Andric 1447a7e6055SDimitry Andric void AMDGPUAsmPrinter::EmitEndOfAsmFile(Module &M) { 1452cab237bSDimitry Andric if (TM.getTargetTriple().getArch() != Triple::amdgcn) 1467a7e6055SDimitry Andric return; 1473ca95b02SDimitry Andric 1482cab237bSDimitry Andric // Following code requires TargetStreamer to be present. 1492cab237bSDimitry Andric if (!getTargetStreamer()) 1502cab237bSDimitry Andric return; 1512cab237bSDimitry Andric 1522cab237bSDimitry Andric // Emit ISA Version (NT_AMD_AMDGPU_ISA). 1532cab237bSDimitry Andric std::string ISAVersionString; 1542cab237bSDimitry Andric raw_string_ostream ISAVersionStream(ISAVersionString); 1552cab237bSDimitry Andric IsaInfo::streamIsaVersion(getSTI(), ISAVersionStream); 1562cab237bSDimitry Andric getTargetStreamer()->EmitISAVersion(ISAVersionStream.str()); 1572cab237bSDimitry Andric 1582cab237bSDimitry Andric // Emit HSA Metadata (NT_AMD_AMDGPU_HSA_METADATA). 1592cab237bSDimitry Andric if (TM.getTargetTriple().getOS() == Triple::AMDHSA) { 1602cab237bSDimitry Andric HSAMetadataStream.end(); 1612cab237bSDimitry Andric getTargetStreamer()->EmitHSAMetadata(HSAMetadataStream.getHSAMetadata()); 1622cab237bSDimitry Andric } 1632cab237bSDimitry Andric 1642cab237bSDimitry Andric // Emit PAL Metadata (NT_AMD_AMDGPU_PAL_METADATA). 1652cab237bSDimitry Andric if (TM.getTargetTriple().getOS() == Triple::AMDPAL) { 1662cab237bSDimitry Andric // Copy the PAL metadata from the map where we collected it into a vector, 1672cab237bSDimitry Andric // then write it as a .note. 1682cab237bSDimitry Andric PALMD::Metadata PALMetadataVector; 1692cab237bSDimitry Andric for (auto i : PALMetadataMap) { 1702cab237bSDimitry Andric PALMetadataVector.push_back(i.first); 1712cab237bSDimitry Andric PALMetadataVector.push_back(i.second); 1722cab237bSDimitry Andric } 1732cab237bSDimitry Andric getTargetStreamer()->EmitPALMetadata(PALMetadataVector); 1742cab237bSDimitry Andric } 175444ed5c5SDimitry Andric } 176444ed5c5SDimitry Andric 177d88c1a5aSDimitry Andric bool AMDGPUAsmPrinter::isBlockOnlyReachableByFallthrough( 178d88c1a5aSDimitry Andric const MachineBasicBlock *MBB) const { 179d88c1a5aSDimitry Andric if (!AsmPrinter::isBlockOnlyReachableByFallthrough(MBB)) 180d88c1a5aSDimitry Andric return false; 181d88c1a5aSDimitry Andric 182d88c1a5aSDimitry Andric if (MBB->empty()) 183d88c1a5aSDimitry Andric return true; 184d88c1a5aSDimitry Andric 185d88c1a5aSDimitry Andric // If this is a block implementing a long branch, an expression relative to 186d88c1a5aSDimitry Andric // the start of the block is needed. to the start of the block. 187d88c1a5aSDimitry Andric // XXX - Is there a smarter way to check this? 188d88c1a5aSDimitry Andric return (MBB->back().getOpcode() != AMDGPU::S_SETPC_B64); 189d88c1a5aSDimitry Andric } 190d88c1a5aSDimitry Andric 1913dac3a9bSDimitry Andric void AMDGPUAsmPrinter::EmitFunctionBodyStart() { 1926bc11b14SDimitry Andric const AMDGPUMachineFunction *MFI = MF->getInfo<AMDGPUMachineFunction>(); 1936bc11b14SDimitry Andric if (!MFI->isEntryFunction()) 1946bc11b14SDimitry Andric return; 1956bc11b14SDimitry Andric 1963dac3a9bSDimitry Andric const AMDGPUSubtarget &STM = MF->getSubtarget<AMDGPUSubtarget>(); 1977a7e6055SDimitry Andric amd_kernel_code_t KernelCode; 19898221d2eSDimitry Andric if (STM.isAmdCodeObjectV2(*MF)) { 199f37b6182SDimitry Andric getAmdKernelCode(KernelCode, CurrentProgramInfo, *MF); 2007a7e6055SDimitry Andric 2017a7e6055SDimitry Andric OutStreamer->SwitchSection(getObjFileLowering().getTextSection()); 2022cab237bSDimitry Andric getTargetStreamer()->EmitAMDKernelCodeT(KernelCode); 2033dac3a9bSDimitry Andric } 2047a7e6055SDimitry Andric 2057a7e6055SDimitry Andric if (TM.getTargetTriple().getOS() != Triple::AMDHSA) 2067a7e6055SDimitry Andric return; 2072cab237bSDimitry Andric 2082cab237bSDimitry Andric HSAMetadataStream.emitKernel(MF->getFunction(), 2092cab237bSDimitry Andric getHSACodeProps(*MF, CurrentProgramInfo), 2102cab237bSDimitry Andric getHSADebugProps(*MF, CurrentProgramInfo)); 2113dac3a9bSDimitry Andric } 2123dac3a9bSDimitry Andric 2137d523365SDimitry Andric void AMDGPUAsmPrinter::EmitFunctionEntryLabel() { 2147d523365SDimitry Andric const SIMachineFunctionInfo *MFI = MF->getInfo<SIMachineFunctionInfo>(); 2157d523365SDimitry Andric const AMDGPUSubtarget &STM = MF->getSubtarget<AMDGPUSubtarget>(); 2167a7e6055SDimitry Andric if (MFI->isEntryFunction() && STM.isAmdCodeObjectV2(*MF)) { 217d88c1a5aSDimitry Andric SmallString<128> SymbolName; 2182cab237bSDimitry Andric getNameWithPrefix(SymbolName, &MF->getFunction()), 2192cab237bSDimitry Andric getTargetStreamer()->EmitAMDGPUSymbolType( 2207a7e6055SDimitry Andric SymbolName, ELF::STT_AMDGPU_HSA_KERNEL); 2217d523365SDimitry Andric } 2222cab237bSDimitry Andric const AMDGPUSubtarget &STI = MF->getSubtarget<AMDGPUSubtarget>(); 2232cab237bSDimitry Andric if (STI.dumpCode()) { 2242cab237bSDimitry Andric // Disassemble function name label to text. 2252cab237bSDimitry Andric DisasmLines.push_back(MF->getName().str() + ":"); 2262cab237bSDimitry Andric DisasmLineMaxLen = std::max(DisasmLineMaxLen, DisasmLines.back().size()); 2272cab237bSDimitry Andric HexLines.push_back(""); 2282cab237bSDimitry Andric } 2298f0fd8f6SDimitry Andric 2307d523365SDimitry Andric AsmPrinter::EmitFunctionEntryLabel(); 2317d523365SDimitry Andric } 2327d523365SDimitry Andric 2332cab237bSDimitry Andric void AMDGPUAsmPrinter::EmitBasicBlockStart(const MachineBasicBlock &MBB) const { 2342cab237bSDimitry Andric const AMDGPUSubtarget &STI = MBB.getParent()->getSubtarget<AMDGPUSubtarget>(); 2352cab237bSDimitry Andric if (STI.dumpCode() && !isBlockOnlyReachableByFallthrough(&MBB)) { 2362cab237bSDimitry Andric // Write a line for the basic block label if it is not only fallthrough. 2372cab237bSDimitry Andric DisasmLines.push_back( 2382cab237bSDimitry Andric (Twine("BB") + Twine(getFunctionNumber()) 2392cab237bSDimitry Andric + "_" + Twine(MBB.getNumber()) + ":").str()); 2402cab237bSDimitry Andric DisasmLineMaxLen = std::max(DisasmLineMaxLen, DisasmLines.back().size()); 2412cab237bSDimitry Andric HexLines.push_back(""); 2422cab237bSDimitry Andric } 2432cab237bSDimitry Andric AsmPrinter::EmitBasicBlockStart(MBB); 2442cab237bSDimitry Andric } 2452cab237bSDimitry Andric 2467d523365SDimitry Andric void AMDGPUAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { 2477d523365SDimitry Andric 2487d523365SDimitry Andric // Group segment variables aren't emitted in HSA. 2492cab237bSDimitry Andric if (AMDGPU::isGroupSegment(GV)) 2507d523365SDimitry Andric return; 2517d523365SDimitry Andric 2523ca95b02SDimitry Andric AsmPrinter::EmitGlobalVariable(GV); 2538f0fd8f6SDimitry Andric } 2548f0fd8f6SDimitry Andric 255f37b6182SDimitry Andric bool AMDGPUAsmPrinter::doFinalization(Module &M) { 256f37b6182SDimitry Andric CallGraphResourceInfo.clear(); 257f37b6182SDimitry Andric return AsmPrinter::doFinalization(M); 258f37b6182SDimitry Andric } 259f37b6182SDimitry Andric 2602cab237bSDimitry Andric // For the amdpal OS type, read the amdgpu.pal.metadata supplied by the 2612cab237bSDimitry Andric // frontend into our PALMetadataMap, ready for per-function modification. It 2622cab237bSDimitry Andric // is a NamedMD containing an MDTuple containing a number of MDNodes each of 2632cab237bSDimitry Andric // which is an integer value, and each two integer values forms a key=value 2642cab237bSDimitry Andric // pair that we store as PALMetadataMap[key]=value in the map. 2652cab237bSDimitry Andric void AMDGPUAsmPrinter::readPALMetadata(Module &M) { 2662cab237bSDimitry Andric auto NamedMD = M.getNamedMetadata("amdgpu.pal.metadata"); 2672cab237bSDimitry Andric if (!NamedMD || !NamedMD->getNumOperands()) 2682cab237bSDimitry Andric return; 2692cab237bSDimitry Andric auto Tuple = dyn_cast<MDTuple>(NamedMD->getOperand(0)); 2702cab237bSDimitry Andric if (!Tuple) 2712cab237bSDimitry Andric return; 2722cab237bSDimitry Andric for (unsigned I = 0, E = Tuple->getNumOperands() & -2; I != E; I += 2) { 2732cab237bSDimitry Andric auto Key = mdconst::dyn_extract<ConstantInt>(Tuple->getOperand(I)); 2742cab237bSDimitry Andric auto Val = mdconst::dyn_extract<ConstantInt>(Tuple->getOperand(I + 1)); 2752cab237bSDimitry Andric if (!Key || !Val) 2762cab237bSDimitry Andric continue; 2772cab237bSDimitry Andric PALMetadataMap[Key->getZExtValue()] = Val->getZExtValue(); 2782cab237bSDimitry Andric } 2792cab237bSDimitry Andric } 2802cab237bSDimitry Andric 281f37b6182SDimitry Andric // Print comments that apply to both callable functions and entry points. 282f37b6182SDimitry Andric void AMDGPUAsmPrinter::emitCommonFunctionComments( 283f37b6182SDimitry Andric uint32_t NumVGPR, 284f37b6182SDimitry Andric uint32_t NumSGPR, 2852cab237bSDimitry Andric uint64_t ScratchSize, 286f37b6182SDimitry Andric uint64_t CodeSize) { 287f37b6182SDimitry Andric OutStreamer->emitRawComment(" codeLenInByte = " + Twine(CodeSize), false); 288f37b6182SDimitry Andric OutStreamer->emitRawComment(" NumSgprs: " + Twine(NumSGPR), false); 289f37b6182SDimitry Andric OutStreamer->emitRawComment(" NumVgprs: " + Twine(NumVGPR), false); 290f37b6182SDimitry Andric OutStreamer->emitRawComment(" ScratchSize: " + Twine(ScratchSize), false); 291f37b6182SDimitry Andric } 292f37b6182SDimitry Andric 2938f0fd8f6SDimitry Andric bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) { 294f37b6182SDimitry Andric CurrentProgramInfo = SIProgramInfo(); 295f37b6182SDimitry Andric 2966bc11b14SDimitry Andric const AMDGPUMachineFunction *MFI = MF.getInfo<AMDGPUMachineFunction>(); 2978f0fd8f6SDimitry Andric 2988f0fd8f6SDimitry Andric // The starting address of all shader programs must be 256 bytes aligned. 2996bc11b14SDimitry Andric // Regular functions just need the basic required instruction alignment. 3006bc11b14SDimitry Andric MF.setAlignment(MFI->isEntryFunction() ? 8 : 2); 3018f0fd8f6SDimitry Andric 3028f0fd8f6SDimitry Andric SetupMachineFunction(MF); 3038f0fd8f6SDimitry Andric 30495ec533aSDimitry Andric const AMDGPUSubtarget &STM = MF.getSubtarget<AMDGPUSubtarget>(); 3058f0fd8f6SDimitry Andric MCContext &Context = getObjFileLowering().getContext(); 30695ec533aSDimitry Andric if (!STM.isAmdHsaOS()) { 3078f0fd8f6SDimitry Andric MCSectionELF *ConfigSection = 3088f0fd8f6SDimitry Andric Context.getELFSection(".AMDGPU.config", ELF::SHT_PROGBITS, 0); 3098f0fd8f6SDimitry Andric OutStreamer->SwitchSection(ConfigSection); 31095ec533aSDimitry Andric } 3118f0fd8f6SDimitry Andric 3123dac3a9bSDimitry Andric if (STM.getGeneration() >= AMDGPUSubtarget::SOUTHERN_ISLANDS) { 313f37b6182SDimitry Andric if (MFI->isEntryFunction()) { 314f37b6182SDimitry Andric getSIProgramInfo(CurrentProgramInfo, MF); 315f37b6182SDimitry Andric } else { 316f37b6182SDimitry Andric auto I = CallGraphResourceInfo.insert( 3172cab237bSDimitry Andric std::make_pair(&MF.getFunction(), SIFunctionResourceInfo())); 318f37b6182SDimitry Andric SIFunctionResourceInfo &Info = I.first->second; 319f37b6182SDimitry Andric assert(I.second && "should only be called once per function"); 320f37b6182SDimitry Andric Info = analyzeResourceUsage(MF); 321f37b6182SDimitry Andric } 322f37b6182SDimitry Andric 3232cab237bSDimitry Andric if (STM.isAmdPalOS()) 3242cab237bSDimitry Andric EmitPALMetadata(MF, CurrentProgramInfo); 3257d523365SDimitry Andric if (!STM.isAmdHsaOS()) { 326f37b6182SDimitry Andric EmitProgramInfoSI(MF, CurrentProgramInfo); 3273dac3a9bSDimitry Andric } 3288f0fd8f6SDimitry Andric } else { 3298f0fd8f6SDimitry Andric EmitProgramInfoR600(MF); 3308f0fd8f6SDimitry Andric } 3318f0fd8f6SDimitry Andric 3328f0fd8f6SDimitry Andric DisasmLines.clear(); 3338f0fd8f6SDimitry Andric HexLines.clear(); 3348f0fd8f6SDimitry Andric DisasmLineMaxLen = 0; 3358f0fd8f6SDimitry Andric 3368f0fd8f6SDimitry Andric EmitFunctionBody(); 3378f0fd8f6SDimitry Andric 3388f0fd8f6SDimitry Andric if (isVerbose()) { 3398f0fd8f6SDimitry Andric MCSectionELF *CommentSection = 3408f0fd8f6SDimitry Andric Context.getELFSection(".AMDGPU.csdata", ELF::SHT_PROGBITS, 0); 3418f0fd8f6SDimitry Andric OutStreamer->SwitchSection(CommentSection); 3428f0fd8f6SDimitry Andric 3438f0fd8f6SDimitry Andric if (STM.getGeneration() >= AMDGPUSubtarget::SOUTHERN_ISLANDS) { 344f37b6182SDimitry Andric if (!MFI->isEntryFunction()) { 3456bc11b14SDimitry Andric OutStreamer->emitRawComment(" Function info:", false); 3462cab237bSDimitry Andric SIFunctionResourceInfo &Info = CallGraphResourceInfo[&MF.getFunction()]; 347f37b6182SDimitry Andric emitCommonFunctionComments( 348f37b6182SDimitry Andric Info.NumVGPR, 349f37b6182SDimitry Andric Info.getTotalNumSGPRs(MF.getSubtarget<SISubtarget>()), 350f37b6182SDimitry Andric Info.PrivateSegmentSize, 351f37b6182SDimitry Andric getFunctionCodeSize(MF)); 352f37b6182SDimitry Andric return false; 3536bc11b14SDimitry Andric } 3546bc11b14SDimitry Andric 355f37b6182SDimitry Andric OutStreamer->emitRawComment(" Kernel info:", false); 356f37b6182SDimitry Andric emitCommonFunctionComments(CurrentProgramInfo.NumVGPR, 357f37b6182SDimitry Andric CurrentProgramInfo.NumSGPR, 358f37b6182SDimitry Andric CurrentProgramInfo.ScratchSize, 359f37b6182SDimitry Andric getFunctionCodeSize(MF)); 360f37b6182SDimitry Andric 361f37b6182SDimitry Andric OutStreamer->emitRawComment( 362f37b6182SDimitry Andric " FloatMode: " + Twine(CurrentProgramInfo.FloatMode), false); 363f37b6182SDimitry Andric OutStreamer->emitRawComment( 364f37b6182SDimitry Andric " IeeeMode: " + Twine(CurrentProgramInfo.IEEEMode), false); 365f37b6182SDimitry Andric OutStreamer->emitRawComment( 366f37b6182SDimitry Andric " LDSByteSize: " + Twine(CurrentProgramInfo.LDSSize) + 3673ca95b02SDimitry Andric " bytes/workgroup (compile time only)", false); 3683ca95b02SDimitry Andric 369f37b6182SDimitry Andric OutStreamer->emitRawComment( 370f37b6182SDimitry Andric " SGPRBlocks: " + Twine(CurrentProgramInfo.SGPRBlocks), false); 371f37b6182SDimitry Andric OutStreamer->emitRawComment( 372f37b6182SDimitry Andric " VGPRBlocks: " + Twine(CurrentProgramInfo.VGPRBlocks), false); 3736bc11b14SDimitry Andric 374f37b6182SDimitry Andric OutStreamer->emitRawComment( 375f37b6182SDimitry Andric " NumSGPRsForWavesPerEU: " + 376f37b6182SDimitry Andric Twine(CurrentProgramInfo.NumSGPRsForWavesPerEU), false); 377f37b6182SDimitry Andric OutStreamer->emitRawComment( 378f37b6182SDimitry Andric " NumVGPRsForWavesPerEU: " + 379f37b6182SDimitry Andric Twine(CurrentProgramInfo.NumVGPRsForWavesPerEU), false); 380d88c1a5aSDimitry Andric 381f37b6182SDimitry Andric OutStreamer->emitRawComment( 382f37b6182SDimitry Andric " ReservedVGPRFirst: " + Twine(CurrentProgramInfo.ReservedVGPRFirst), 3833ca95b02SDimitry Andric false); 384f37b6182SDimitry Andric OutStreamer->emitRawComment( 385f37b6182SDimitry Andric " ReservedVGPRCount: " + Twine(CurrentProgramInfo.ReservedVGPRCount), 3863ca95b02SDimitry Andric false); 3873ca95b02SDimitry Andric 3883ca95b02SDimitry Andric if (MF.getSubtarget<SISubtarget>().debuggerEmitPrologue()) { 389f37b6182SDimitry Andric OutStreamer->emitRawComment( 390f37b6182SDimitry Andric " DebuggerWavefrontPrivateSegmentOffsetSGPR: s" + 391f37b6182SDimitry Andric Twine(CurrentProgramInfo.DebuggerWavefrontPrivateSegmentOffsetSGPR), false); 392f37b6182SDimitry Andric OutStreamer->emitRawComment( 393f37b6182SDimitry Andric " DebuggerPrivateSegmentBufferSGPR: s" + 394f37b6182SDimitry Andric Twine(CurrentProgramInfo.DebuggerPrivateSegmentBufferSGPR), false); 3953ca95b02SDimitry Andric } 3967d523365SDimitry Andric 397f37b6182SDimitry Andric OutStreamer->emitRawComment( 398f37b6182SDimitry Andric " COMPUTE_PGM_RSRC2:USER_SGPR: " + 399f37b6182SDimitry Andric Twine(G_00B84C_USER_SGPR(CurrentProgramInfo.ComputePGMRSrc2)), false); 400f37b6182SDimitry Andric OutStreamer->emitRawComment( 401f37b6182SDimitry Andric " COMPUTE_PGM_RSRC2:TRAP_HANDLER: " + 402f37b6182SDimitry Andric Twine(G_00B84C_TRAP_HANDLER(CurrentProgramInfo.ComputePGMRSrc2)), false); 403f37b6182SDimitry Andric OutStreamer->emitRawComment( 404f37b6182SDimitry Andric " COMPUTE_PGM_RSRC2:TGID_X_EN: " + 405f37b6182SDimitry Andric Twine(G_00B84C_TGID_X_EN(CurrentProgramInfo.ComputePGMRSrc2)), false); 406f37b6182SDimitry Andric OutStreamer->emitRawComment( 407f37b6182SDimitry Andric " COMPUTE_PGM_RSRC2:TGID_Y_EN: " + 408f37b6182SDimitry Andric Twine(G_00B84C_TGID_Y_EN(CurrentProgramInfo.ComputePGMRSrc2)), false); 409f37b6182SDimitry Andric OutStreamer->emitRawComment( 410f37b6182SDimitry Andric " COMPUTE_PGM_RSRC2:TGID_Z_EN: " + 411f37b6182SDimitry Andric Twine(G_00B84C_TGID_Z_EN(CurrentProgramInfo.ComputePGMRSrc2)), false); 412f37b6182SDimitry Andric OutStreamer->emitRawComment( 413f37b6182SDimitry Andric " COMPUTE_PGM_RSRC2:TIDIG_COMP_CNT: " + 414f37b6182SDimitry Andric Twine(G_00B84C_TIDIG_COMP_CNT(CurrentProgramInfo.ComputePGMRSrc2)), 4157d523365SDimitry Andric false); 4168f0fd8f6SDimitry Andric } else { 4178f0fd8f6SDimitry Andric R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>(); 4188f0fd8f6SDimitry Andric OutStreamer->emitRawComment( 419d88c1a5aSDimitry Andric Twine("SQ_PGM_RESOURCES:STACK_SIZE = " + Twine(MFI->CFStackSize))); 4208f0fd8f6SDimitry Andric } 4218f0fd8f6SDimitry Andric } 4228f0fd8f6SDimitry Andric 4238f0fd8f6SDimitry Andric if (STM.dumpCode()) { 4248f0fd8f6SDimitry Andric 4258f0fd8f6SDimitry Andric OutStreamer->SwitchSection( 4268f0fd8f6SDimitry Andric Context.getELFSection(".AMDGPU.disasm", ELF::SHT_NOTE, 0)); 4278f0fd8f6SDimitry Andric 4288f0fd8f6SDimitry Andric for (size_t i = 0; i < DisasmLines.size(); ++i) { 4292cab237bSDimitry Andric std::string Comment = "\n"; 4302cab237bSDimitry Andric if (!HexLines[i].empty()) { 4312cab237bSDimitry Andric Comment = std::string(DisasmLineMaxLen - DisasmLines[i].size(), ' '); 4328f0fd8f6SDimitry Andric Comment += " ; " + HexLines[i] + "\n"; 4332cab237bSDimitry Andric } 4348f0fd8f6SDimitry Andric 4358f0fd8f6SDimitry Andric OutStreamer->EmitBytes(StringRef(DisasmLines[i])); 4368f0fd8f6SDimitry Andric OutStreamer->EmitBytes(StringRef(Comment)); 4378f0fd8f6SDimitry Andric } 4388f0fd8f6SDimitry Andric } 4398f0fd8f6SDimitry Andric 4408f0fd8f6SDimitry Andric return false; 4418f0fd8f6SDimitry Andric } 4428f0fd8f6SDimitry Andric 4438f0fd8f6SDimitry Andric void AMDGPUAsmPrinter::EmitProgramInfoR600(const MachineFunction &MF) { 4448f0fd8f6SDimitry Andric unsigned MaxGPR = 0; 4458f0fd8f6SDimitry Andric bool killPixel = false; 4463ca95b02SDimitry Andric const R600Subtarget &STM = MF.getSubtarget<R600Subtarget>(); 4473ca95b02SDimitry Andric const R600RegisterInfo *RI = STM.getRegisterInfo(); 4488f0fd8f6SDimitry Andric const R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>(); 4498f0fd8f6SDimitry Andric 4508f0fd8f6SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 4518f0fd8f6SDimitry Andric for (const MachineInstr &MI : MBB) { 4528f0fd8f6SDimitry Andric if (MI.getOpcode() == AMDGPU::KILLGT) 4538f0fd8f6SDimitry Andric killPixel = true; 4548f0fd8f6SDimitry Andric unsigned numOperands = MI.getNumOperands(); 4558f0fd8f6SDimitry Andric for (unsigned op_idx = 0; op_idx < numOperands; op_idx++) { 4568f0fd8f6SDimitry Andric const MachineOperand &MO = MI.getOperand(op_idx); 4578f0fd8f6SDimitry Andric if (!MO.isReg()) 4588f0fd8f6SDimitry Andric continue; 4596bc11b14SDimitry Andric unsigned HWReg = RI->getHWRegIndex(MO.getReg()); 4608f0fd8f6SDimitry Andric 4618f0fd8f6SDimitry Andric // Register with value > 127 aren't GPR 4628f0fd8f6SDimitry Andric if (HWReg > 127) 4638f0fd8f6SDimitry Andric continue; 4648f0fd8f6SDimitry Andric MaxGPR = std::max(MaxGPR, HWReg); 4658f0fd8f6SDimitry Andric } 4668f0fd8f6SDimitry Andric } 4678f0fd8f6SDimitry Andric } 4688f0fd8f6SDimitry Andric 4698f0fd8f6SDimitry Andric unsigned RsrcReg; 4703ca95b02SDimitry Andric if (STM.getGeneration() >= R600Subtarget::EVERGREEN) { 4718f0fd8f6SDimitry Andric // Evergreen / Northern Islands 4722cab237bSDimitry Andric switch (MF.getFunction().getCallingConv()) { 473d88c1a5aSDimitry Andric default: LLVM_FALLTHROUGH; 4743ca95b02SDimitry Andric case CallingConv::AMDGPU_CS: RsrcReg = R_0288D4_SQ_PGM_RESOURCES_LS; break; 4753ca95b02SDimitry Andric case CallingConv::AMDGPU_GS: RsrcReg = R_028878_SQ_PGM_RESOURCES_GS; break; 4763ca95b02SDimitry Andric case CallingConv::AMDGPU_PS: RsrcReg = R_028844_SQ_PGM_RESOURCES_PS; break; 4773ca95b02SDimitry Andric case CallingConv::AMDGPU_VS: RsrcReg = R_028860_SQ_PGM_RESOURCES_VS; break; 4788f0fd8f6SDimitry Andric } 4798f0fd8f6SDimitry Andric } else { 4808f0fd8f6SDimitry Andric // R600 / R700 4812cab237bSDimitry Andric switch (MF.getFunction().getCallingConv()) { 482d88c1a5aSDimitry Andric default: LLVM_FALLTHROUGH; 483d88c1a5aSDimitry Andric case CallingConv::AMDGPU_GS: LLVM_FALLTHROUGH; 484d88c1a5aSDimitry Andric case CallingConv::AMDGPU_CS: LLVM_FALLTHROUGH; 4853ca95b02SDimitry Andric case CallingConv::AMDGPU_VS: RsrcReg = R_028868_SQ_PGM_RESOURCES_VS; break; 4863ca95b02SDimitry Andric case CallingConv::AMDGPU_PS: RsrcReg = R_028850_SQ_PGM_RESOURCES_PS; break; 4878f0fd8f6SDimitry Andric } 4888f0fd8f6SDimitry Andric } 4898f0fd8f6SDimitry Andric 4908f0fd8f6SDimitry Andric OutStreamer->EmitIntValue(RsrcReg, 4); 4918f0fd8f6SDimitry Andric OutStreamer->EmitIntValue(S_NUM_GPRS(MaxGPR + 1) | 492d88c1a5aSDimitry Andric S_STACK_SIZE(MFI->CFStackSize), 4); 4938f0fd8f6SDimitry Andric OutStreamer->EmitIntValue(R_02880C_DB_SHADER_CONTROL, 4); 4948f0fd8f6SDimitry Andric OutStreamer->EmitIntValue(S_02880C_KILL_ENABLE(killPixel), 4); 4958f0fd8f6SDimitry Andric 4962cab237bSDimitry Andric if (AMDGPU::isCompute(MF.getFunction().getCallingConv())) { 4978f0fd8f6SDimitry Andric OutStreamer->EmitIntValue(R_0288E8_SQ_LDS_ALLOC, 4); 498d88c1a5aSDimitry Andric OutStreamer->EmitIntValue(alignTo(MFI->getLDSSize(), 4) >> 2, 4); 4998f0fd8f6SDimitry Andric } 5008f0fd8f6SDimitry Andric } 5018f0fd8f6SDimitry Andric 5026bc11b14SDimitry Andric uint64_t AMDGPUAsmPrinter::getFunctionCodeSize(const MachineFunction &MF) const { 5033ca95b02SDimitry Andric const SISubtarget &STM = MF.getSubtarget<SISubtarget>(); 5043ca95b02SDimitry Andric const SIInstrInfo *TII = STM.getInstrInfo(); 5058f0fd8f6SDimitry Andric 5066bc11b14SDimitry Andric uint64_t CodeSize = 0; 5076bc11b14SDimitry Andric 5088f0fd8f6SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 5098f0fd8f6SDimitry Andric for (const MachineInstr &MI : MBB) { 5108f0fd8f6SDimitry Andric // TODO: CodeSize should account for multiple functions. 5119a4b3118SDimitry Andric 5129a4b3118SDimitry Andric // TODO: Should we count size of debug info? 5139a4b3118SDimitry Andric if (MI.isDebugValue()) 5149a4b3118SDimitry Andric continue; 5159a4b3118SDimitry Andric 5163ca95b02SDimitry Andric CodeSize += TII->getInstSizeInBytes(MI); 5176bc11b14SDimitry Andric } 5186bc11b14SDimitry Andric } 5198f0fd8f6SDimitry Andric 5206bc11b14SDimitry Andric return CodeSize; 5216bc11b14SDimitry Andric } 5228f0fd8f6SDimitry Andric 5236bc11b14SDimitry Andric static bool hasAnyNonFlatUseOfReg(const MachineRegisterInfo &MRI, 5246bc11b14SDimitry Andric const SIInstrInfo &TII, 5256bc11b14SDimitry Andric unsigned Reg) { 5266bc11b14SDimitry Andric for (const MachineOperand &UseOp : MRI.reg_operands(Reg)) { 5276bc11b14SDimitry Andric if (!UseOp.isImplicit() || !TII.isFLAT(*UseOp.getParent())) 5286bc11b14SDimitry Andric return true; 5296bc11b14SDimitry Andric } 5308f0fd8f6SDimitry Andric 5316bc11b14SDimitry Andric return false; 5326bc11b14SDimitry Andric } 5337d523365SDimitry Andric 534f37b6182SDimitry Andric static unsigned getNumExtraSGPRs(const SISubtarget &ST, 535f37b6182SDimitry Andric bool VCCUsed, 536f37b6182SDimitry Andric bool FlatScrUsed) { 537f37b6182SDimitry Andric unsigned ExtraSGPRs = 0; 538f37b6182SDimitry Andric if (VCCUsed) 539f37b6182SDimitry Andric ExtraSGPRs = 2; 540f37b6182SDimitry Andric 541f37b6182SDimitry Andric if (ST.getGeneration() < SISubtarget::VOLCANIC_ISLANDS) { 542f37b6182SDimitry Andric if (FlatScrUsed) 543f37b6182SDimitry Andric ExtraSGPRs = 4; 544f37b6182SDimitry Andric } else { 545f37b6182SDimitry Andric if (ST.isXNACKEnabled()) 546f37b6182SDimitry Andric ExtraSGPRs = 4; 547f37b6182SDimitry Andric 548f37b6182SDimitry Andric if (FlatScrUsed) 549f37b6182SDimitry Andric ExtraSGPRs = 6; 550f37b6182SDimitry Andric } 551f37b6182SDimitry Andric 552f37b6182SDimitry Andric return ExtraSGPRs; 553f37b6182SDimitry Andric } 554f37b6182SDimitry Andric 555f37b6182SDimitry Andric int32_t AMDGPUAsmPrinter::SIFunctionResourceInfo::getTotalNumSGPRs( 556f37b6182SDimitry Andric const SISubtarget &ST) const { 557f37b6182SDimitry Andric return NumExplicitSGPR + getNumExtraSGPRs(ST, UsesVCC, UsesFlatScratch); 558f37b6182SDimitry Andric } 559f37b6182SDimitry Andric 560f37b6182SDimitry Andric AMDGPUAsmPrinter::SIFunctionResourceInfo AMDGPUAsmPrinter::analyzeResourceUsage( 5616bc11b14SDimitry Andric const MachineFunction &MF) const { 562f37b6182SDimitry Andric SIFunctionResourceInfo Info; 563f37b6182SDimitry Andric 5646bc11b14SDimitry Andric const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 565f37b6182SDimitry Andric const SISubtarget &ST = MF.getSubtarget<SISubtarget>(); 566f37b6182SDimitry Andric const MachineFrameInfo &FrameInfo = MF.getFrameInfo(); 5676bc11b14SDimitry Andric const MachineRegisterInfo &MRI = MF.getRegInfo(); 568f37b6182SDimitry Andric const SIInstrInfo *TII = ST.getInstrInfo(); 569f37b6182SDimitry Andric const SIRegisterInfo &TRI = TII->getRegisterInfo(); 5707d523365SDimitry Andric 571f37b6182SDimitry Andric Info.UsesFlatScratch = MRI.isPhysRegUsed(AMDGPU::FLAT_SCR_LO) || 572f37b6182SDimitry Andric MRI.isPhysRegUsed(AMDGPU::FLAT_SCR_HI); 5737d523365SDimitry Andric 574f37b6182SDimitry Andric // Even if FLAT_SCRATCH is implicitly used, it has no effect if flat 575f37b6182SDimitry Andric // instructions aren't used to access the scratch buffer. Inline assembly may 576f37b6182SDimitry Andric // need it though. 577f37b6182SDimitry Andric // 578f37b6182SDimitry Andric // If we only have implicit uses of flat_scr on flat instructions, it is not 579f37b6182SDimitry Andric // really needed. 580f37b6182SDimitry Andric if (Info.UsesFlatScratch && !MFI->hasFlatScratchInit() && 581f37b6182SDimitry Andric (!hasAnyNonFlatUseOfReg(MRI, *TII, AMDGPU::FLAT_SCR) && 582f37b6182SDimitry Andric !hasAnyNonFlatUseOfReg(MRI, *TII, AMDGPU::FLAT_SCR_LO) && 583f37b6182SDimitry Andric !hasAnyNonFlatUseOfReg(MRI, *TII, AMDGPU::FLAT_SCR_HI))) { 584f37b6182SDimitry Andric Info.UsesFlatScratch = false; 585f37b6182SDimitry Andric } 586f37b6182SDimitry Andric 587f37b6182SDimitry Andric Info.HasDynamicallySizedStack = FrameInfo.hasVarSizedObjects(); 588f37b6182SDimitry Andric Info.PrivateSegmentSize = FrameInfo.getStackSize(); 589f37b6182SDimitry Andric 590f9448bf3SDimitry Andric 591f37b6182SDimitry Andric Info.UsesVCC = MRI.isPhysRegUsed(AMDGPU::VCC_LO) || 592f37b6182SDimitry Andric MRI.isPhysRegUsed(AMDGPU::VCC_HI); 593f37b6182SDimitry Andric 594f37b6182SDimitry Andric // If there are no calls, MachineRegisterInfo can tell us the used register 595f37b6182SDimitry Andric // count easily. 5962cab237bSDimitry Andric // A tail call isn't considered a call for MachineFrameInfo's purposes. 5972cab237bSDimitry Andric if (!FrameInfo.hasCalls() && !FrameInfo.hasTailCall()) { 598f37b6182SDimitry Andric MCPhysReg HighestVGPRReg = AMDGPU::NoRegister; 5996bc11b14SDimitry Andric for (MCPhysReg Reg : reverse(AMDGPU::VGPR_32RegClass.getRegisters())) { 6006bc11b14SDimitry Andric if (MRI.isPhysRegUsed(Reg)) { 601f37b6182SDimitry Andric HighestVGPRReg = Reg; 6027d523365SDimitry Andric break; 6038f0fd8f6SDimitry Andric } 6046bc11b14SDimitry Andric } 6058f0fd8f6SDimitry Andric 606f37b6182SDimitry Andric MCPhysReg HighestSGPRReg = AMDGPU::NoRegister; 6076bc11b14SDimitry Andric for (MCPhysReg Reg : reverse(AMDGPU::SGPR_32RegClass.getRegisters())) { 6086bc11b14SDimitry Andric if (MRI.isPhysRegUsed(Reg)) { 609f37b6182SDimitry Andric HighestSGPRReg = Reg; 6106bc11b14SDimitry Andric break; 6118f0fd8f6SDimitry Andric } 6128f0fd8f6SDimitry Andric } 6138f0fd8f6SDimitry Andric 6146bc11b14SDimitry Andric // We found the maximum register index. They start at 0, so add one to get the 6156bc11b14SDimitry Andric // number of registers. 616f37b6182SDimitry Andric Info.NumVGPR = HighestVGPRReg == AMDGPU::NoRegister ? 0 : 617f37b6182SDimitry Andric TRI.getHWRegIndex(HighestVGPRReg) + 1; 618f37b6182SDimitry Andric Info.NumExplicitSGPR = HighestSGPRReg == AMDGPU::NoRegister ? 0 : 619f37b6182SDimitry Andric TRI.getHWRegIndex(HighestSGPRReg) + 1; 620444ed5c5SDimitry Andric 621f37b6182SDimitry Andric return Info; 6226bc11b14SDimitry Andric } 6236bc11b14SDimitry Andric 6242cab237bSDimitry Andric int32_t MaxVGPR = -1; 6252cab237bSDimitry Andric int32_t MaxSGPR = -1; 6262cab237bSDimitry Andric uint64_t CalleeFrameSize = 0; 6272cab237bSDimitry Andric 6282cab237bSDimitry Andric for (const MachineBasicBlock &MBB : MF) { 6292cab237bSDimitry Andric for (const MachineInstr &MI : MBB) { 6302cab237bSDimitry Andric // TODO: Check regmasks? Do they occur anywhere except calls? 6312cab237bSDimitry Andric for (const MachineOperand &MO : MI.operands()) { 6322cab237bSDimitry Andric unsigned Width = 0; 6332cab237bSDimitry Andric bool IsSGPR = false; 6342cab237bSDimitry Andric 6352cab237bSDimitry Andric if (!MO.isReg()) 6362cab237bSDimitry Andric continue; 6372cab237bSDimitry Andric 6382cab237bSDimitry Andric unsigned Reg = MO.getReg(); 6392cab237bSDimitry Andric switch (Reg) { 6402cab237bSDimitry Andric case AMDGPU::EXEC: 6412cab237bSDimitry Andric case AMDGPU::EXEC_LO: 6422cab237bSDimitry Andric case AMDGPU::EXEC_HI: 6432cab237bSDimitry Andric case AMDGPU::SCC: 6442cab237bSDimitry Andric case AMDGPU::M0: 6452cab237bSDimitry Andric case AMDGPU::SRC_SHARED_BASE: 6462cab237bSDimitry Andric case AMDGPU::SRC_SHARED_LIMIT: 6472cab237bSDimitry Andric case AMDGPU::SRC_PRIVATE_BASE: 6482cab237bSDimitry Andric case AMDGPU::SRC_PRIVATE_LIMIT: 6492cab237bSDimitry Andric continue; 6502cab237bSDimitry Andric 6512cab237bSDimitry Andric case AMDGPU::NoRegister: 6522cab237bSDimitry Andric assert(MI.isDebugValue()); 6532cab237bSDimitry Andric continue; 6542cab237bSDimitry Andric 6552cab237bSDimitry Andric case AMDGPU::VCC: 6562cab237bSDimitry Andric case AMDGPU::VCC_LO: 6572cab237bSDimitry Andric case AMDGPU::VCC_HI: 6582cab237bSDimitry Andric Info.UsesVCC = true; 6592cab237bSDimitry Andric continue; 6602cab237bSDimitry Andric 6612cab237bSDimitry Andric case AMDGPU::FLAT_SCR: 6622cab237bSDimitry Andric case AMDGPU::FLAT_SCR_LO: 6632cab237bSDimitry Andric case AMDGPU::FLAT_SCR_HI: 6642cab237bSDimitry Andric continue; 6652cab237bSDimitry Andric 6662cab237bSDimitry Andric case AMDGPU::TBA: 6672cab237bSDimitry Andric case AMDGPU::TBA_LO: 6682cab237bSDimitry Andric case AMDGPU::TBA_HI: 6692cab237bSDimitry Andric case AMDGPU::TMA: 6702cab237bSDimitry Andric case AMDGPU::TMA_LO: 6712cab237bSDimitry Andric case AMDGPU::TMA_HI: 6722cab237bSDimitry Andric llvm_unreachable("trap handler registers should not be used"); 6732cab237bSDimitry Andric 6742cab237bSDimitry Andric default: 6752cab237bSDimitry Andric break; 6762cab237bSDimitry Andric } 6772cab237bSDimitry Andric 6782cab237bSDimitry Andric if (AMDGPU::SReg_32RegClass.contains(Reg)) { 6792cab237bSDimitry Andric assert(!AMDGPU::TTMP_32RegClass.contains(Reg) && 6802cab237bSDimitry Andric "trap handler registers should not be used"); 6812cab237bSDimitry Andric IsSGPR = true; 6822cab237bSDimitry Andric Width = 1; 6832cab237bSDimitry Andric } else if (AMDGPU::VGPR_32RegClass.contains(Reg)) { 6842cab237bSDimitry Andric IsSGPR = false; 6852cab237bSDimitry Andric Width = 1; 6862cab237bSDimitry Andric } else if (AMDGPU::SReg_64RegClass.contains(Reg)) { 6872cab237bSDimitry Andric assert(!AMDGPU::TTMP_64RegClass.contains(Reg) && 6882cab237bSDimitry Andric "trap handler registers should not be used"); 6892cab237bSDimitry Andric IsSGPR = true; 6902cab237bSDimitry Andric Width = 2; 6912cab237bSDimitry Andric } else if (AMDGPU::VReg_64RegClass.contains(Reg)) { 6922cab237bSDimitry Andric IsSGPR = false; 6932cab237bSDimitry Andric Width = 2; 6942cab237bSDimitry Andric } else if (AMDGPU::VReg_96RegClass.contains(Reg)) { 6952cab237bSDimitry Andric IsSGPR = false; 6962cab237bSDimitry Andric Width = 3; 6972cab237bSDimitry Andric } else if (AMDGPU::SReg_128RegClass.contains(Reg)) { 6982cab237bSDimitry Andric IsSGPR = true; 6992cab237bSDimitry Andric Width = 4; 7002cab237bSDimitry Andric } else if (AMDGPU::VReg_128RegClass.contains(Reg)) { 7012cab237bSDimitry Andric IsSGPR = false; 7022cab237bSDimitry Andric Width = 4; 7032cab237bSDimitry Andric } else if (AMDGPU::SReg_256RegClass.contains(Reg)) { 7042cab237bSDimitry Andric IsSGPR = true; 7052cab237bSDimitry Andric Width = 8; 7062cab237bSDimitry Andric } else if (AMDGPU::VReg_256RegClass.contains(Reg)) { 7072cab237bSDimitry Andric IsSGPR = false; 7082cab237bSDimitry Andric Width = 8; 7092cab237bSDimitry Andric } else if (AMDGPU::SReg_512RegClass.contains(Reg)) { 7102cab237bSDimitry Andric IsSGPR = true; 7112cab237bSDimitry Andric Width = 16; 7122cab237bSDimitry Andric } else if (AMDGPU::VReg_512RegClass.contains(Reg)) { 7132cab237bSDimitry Andric IsSGPR = false; 7142cab237bSDimitry Andric Width = 16; 7152cab237bSDimitry Andric } else { 7162cab237bSDimitry Andric llvm_unreachable("Unknown register class"); 7172cab237bSDimitry Andric } 7182cab237bSDimitry Andric unsigned HWReg = TRI.getHWRegIndex(Reg); 7192cab237bSDimitry Andric int MaxUsed = HWReg + Width - 1; 7202cab237bSDimitry Andric if (IsSGPR) { 7212cab237bSDimitry Andric MaxSGPR = MaxUsed > MaxSGPR ? MaxUsed : MaxSGPR; 7222cab237bSDimitry Andric } else { 7232cab237bSDimitry Andric MaxVGPR = MaxUsed > MaxVGPR ? MaxUsed : MaxVGPR; 7242cab237bSDimitry Andric } 7252cab237bSDimitry Andric } 7262cab237bSDimitry Andric 7272cab237bSDimitry Andric if (MI.isCall()) { 7282cab237bSDimitry Andric // Pseudo used just to encode the underlying global. Is there a better 7292cab237bSDimitry Andric // way to track this? 7302cab237bSDimitry Andric 7312cab237bSDimitry Andric const MachineOperand *CalleeOp 7322cab237bSDimitry Andric = TII->getNamedOperand(MI, AMDGPU::OpName::callee); 7332cab237bSDimitry Andric const Function *Callee = cast<Function>(CalleeOp->getGlobal()); 7342cab237bSDimitry Andric if (Callee->isDeclaration()) { 7352cab237bSDimitry Andric // If this is a call to an external function, we can't do much. Make 7362cab237bSDimitry Andric // conservative guesses. 7372cab237bSDimitry Andric 7382cab237bSDimitry Andric // 48 SGPRs - vcc, - flat_scr, -xnack 7392cab237bSDimitry Andric int MaxSGPRGuess = 47 - getNumExtraSGPRs(ST, true, 7402cab237bSDimitry Andric ST.hasFlatAddressSpace()); 7412cab237bSDimitry Andric MaxSGPR = std::max(MaxSGPR, MaxSGPRGuess); 7422cab237bSDimitry Andric MaxVGPR = std::max(MaxVGPR, 23); 7432cab237bSDimitry Andric 7442cab237bSDimitry Andric CalleeFrameSize = std::max(CalleeFrameSize, UINT64_C(16384)); 7452cab237bSDimitry Andric Info.UsesVCC = true; 7462cab237bSDimitry Andric Info.UsesFlatScratch = ST.hasFlatAddressSpace(); 7472cab237bSDimitry Andric Info.HasDynamicallySizedStack = true; 7482cab237bSDimitry Andric } else { 7492cab237bSDimitry Andric // We force CodeGen to run in SCC order, so the callee's register 7502cab237bSDimitry Andric // usage etc. should be the cumulative usage of all callees. 7512cab237bSDimitry Andric auto I = CallGraphResourceInfo.find(Callee); 7522cab237bSDimitry Andric assert(I != CallGraphResourceInfo.end() && 7532cab237bSDimitry Andric "callee should have been handled before caller"); 7542cab237bSDimitry Andric 7552cab237bSDimitry Andric MaxSGPR = std::max(I->second.NumExplicitSGPR - 1, MaxSGPR); 7562cab237bSDimitry Andric MaxVGPR = std::max(I->second.NumVGPR - 1, MaxVGPR); 7572cab237bSDimitry Andric CalleeFrameSize 7582cab237bSDimitry Andric = std::max(I->second.PrivateSegmentSize, CalleeFrameSize); 7592cab237bSDimitry Andric Info.UsesVCC |= I->second.UsesVCC; 7602cab237bSDimitry Andric Info.UsesFlatScratch |= I->second.UsesFlatScratch; 7612cab237bSDimitry Andric Info.HasDynamicallySizedStack |= I->second.HasDynamicallySizedStack; 7622cab237bSDimitry Andric Info.HasRecursion |= I->second.HasRecursion; 7632cab237bSDimitry Andric } 7642cab237bSDimitry Andric 7652cab237bSDimitry Andric if (!Callee->doesNotRecurse()) 7662cab237bSDimitry Andric Info.HasRecursion = true; 7672cab237bSDimitry Andric } 7682cab237bSDimitry Andric } 7692cab237bSDimitry Andric } 7702cab237bSDimitry Andric 7712cab237bSDimitry Andric Info.NumExplicitSGPR = MaxSGPR + 1; 7722cab237bSDimitry Andric Info.NumVGPR = MaxVGPR + 1; 7732cab237bSDimitry Andric Info.PrivateSegmentSize += CalleeFrameSize; 7742cab237bSDimitry Andric 7752cab237bSDimitry Andric return Info; 7762cab237bSDimitry Andric } 7772cab237bSDimitry Andric 778f37b6182SDimitry Andric void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo, 779f37b6182SDimitry Andric const MachineFunction &MF) { 780f37b6182SDimitry Andric SIFunctionResourceInfo Info = analyzeResourceUsage(MF); 781f37b6182SDimitry Andric 782f37b6182SDimitry Andric ProgInfo.NumVGPR = Info.NumVGPR; 783f37b6182SDimitry Andric ProgInfo.NumSGPR = Info.NumExplicitSGPR; 784f37b6182SDimitry Andric ProgInfo.ScratchSize = Info.PrivateSegmentSize; 785f37b6182SDimitry Andric ProgInfo.VCCUsed = Info.UsesVCC; 786f37b6182SDimitry Andric ProgInfo.FlatUsed = Info.UsesFlatScratch; 787f37b6182SDimitry Andric ProgInfo.DynamicCallStack = Info.HasDynamicallySizedStack || Info.HasRecursion; 788f37b6182SDimitry Andric 7892cab237bSDimitry Andric if (!isUInt<32>(ProgInfo.ScratchSize)) { 7902cab237bSDimitry Andric DiagnosticInfoStackSize DiagStackSize(MF.getFunction(), 7912cab237bSDimitry Andric ProgInfo.ScratchSize, DS_Error); 7922cab237bSDimitry Andric MF.getFunction().getContext().diagnose(DiagStackSize); 7932cab237bSDimitry Andric } 7942cab237bSDimitry Andric 795f37b6182SDimitry Andric const SISubtarget &STM = MF.getSubtarget<SISubtarget>(); 796f37b6182SDimitry Andric const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 797f37b6182SDimitry Andric const SIInstrInfo *TII = STM.getInstrInfo(); 798f37b6182SDimitry Andric const SIRegisterInfo *RI = &TII->getRegisterInfo(); 799f37b6182SDimitry Andric 800f37b6182SDimitry Andric unsigned ExtraSGPRs = getNumExtraSGPRs(STM, 801f37b6182SDimitry Andric ProgInfo.VCCUsed, 802f37b6182SDimitry Andric ProgInfo.FlatUsed); 8037a7e6055SDimitry Andric unsigned ExtraVGPRs = STM.getReservedNumVGPRs(MF); 8043ca95b02SDimitry Andric 805d88c1a5aSDimitry Andric // Check the addressable register limit before we add ExtraSGPRs. 806d88c1a5aSDimitry Andric if (STM.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS && 807d88c1a5aSDimitry Andric !STM.hasSGPRInitBug()) { 8087a7e6055SDimitry Andric unsigned MaxAddressableNumSGPRs = STM.getAddressableNumSGPRs(); 8096bc11b14SDimitry Andric if (ProgInfo.NumSGPR > MaxAddressableNumSGPRs) { 810d88c1a5aSDimitry Andric // This can happen due to a compiler bug or when using inline asm. 8112cab237bSDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 8122cab237bSDimitry Andric DiagnosticInfoResourceLimit Diag(MF.getFunction(), 813d88c1a5aSDimitry Andric "addressable scalar registers", 8146bc11b14SDimitry Andric ProgInfo.NumSGPR, DS_Error, 8157a7e6055SDimitry Andric DK_ResourceLimit, 8167a7e6055SDimitry Andric MaxAddressableNumSGPRs); 817d88c1a5aSDimitry Andric Ctx.diagnose(Diag); 8186bc11b14SDimitry Andric ProgInfo.NumSGPR = MaxAddressableNumSGPRs - 1; 819d88c1a5aSDimitry Andric } 820d88c1a5aSDimitry Andric } 821d88c1a5aSDimitry Andric 822d88c1a5aSDimitry Andric // Account for extra SGPRs and VGPRs reserved for debugger use. 8236bc11b14SDimitry Andric ProgInfo.NumSGPR += ExtraSGPRs; 8246bc11b14SDimitry Andric ProgInfo.NumVGPR += ExtraVGPRs; 8258f0fd8f6SDimitry Andric 826d88c1a5aSDimitry Andric // Adjust number of registers used to meet default/requested minimum/maximum 827d88c1a5aSDimitry Andric // number of waves per execution unit request. 828d88c1a5aSDimitry Andric ProgInfo.NumSGPRsForWavesPerEU = std::max( 8296bc11b14SDimitry Andric std::max(ProgInfo.NumSGPR, 1u), STM.getMinNumSGPRs(MFI->getMaxWavesPerEU())); 830d88c1a5aSDimitry Andric ProgInfo.NumVGPRsForWavesPerEU = std::max( 8316bc11b14SDimitry Andric std::max(ProgInfo.NumVGPR, 1u), STM.getMinNumVGPRs(MFI->getMaxWavesPerEU())); 832d88c1a5aSDimitry Andric 833d88c1a5aSDimitry Andric if (STM.getGeneration() <= AMDGPUSubtarget::SEA_ISLANDS || 834d88c1a5aSDimitry Andric STM.hasSGPRInitBug()) { 8357a7e6055SDimitry Andric unsigned MaxAddressableNumSGPRs = STM.getAddressableNumSGPRs(); 8367a7e6055SDimitry Andric if (ProgInfo.NumSGPR > MaxAddressableNumSGPRs) { 8377a7e6055SDimitry Andric // This can happen due to a compiler bug or when using inline asm to use 8387a7e6055SDimitry Andric // the registers which are usually reserved for vcc etc. 8392cab237bSDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 8402cab237bSDimitry Andric DiagnosticInfoResourceLimit Diag(MF.getFunction(), 841d88c1a5aSDimitry Andric "scalar registers", 842d88c1a5aSDimitry Andric ProgInfo.NumSGPR, DS_Error, 8437a7e6055SDimitry Andric DK_ResourceLimit, 8447a7e6055SDimitry Andric MaxAddressableNumSGPRs); 8453ca95b02SDimitry Andric Ctx.diagnose(Diag); 8467a7e6055SDimitry Andric ProgInfo.NumSGPR = MaxAddressableNumSGPRs; 8477a7e6055SDimitry Andric ProgInfo.NumSGPRsForWavesPerEU = MaxAddressableNumSGPRs; 848d88c1a5aSDimitry Andric } 8498f0fd8f6SDimitry Andric } 8508f0fd8f6SDimitry Andric 851d88c1a5aSDimitry Andric if (STM.hasSGPRInitBug()) { 8527a7e6055SDimitry Andric ProgInfo.NumSGPR = 8537a7e6055SDimitry Andric AMDGPU::IsaInfo::FIXED_NUM_SGPRS_FOR_INIT_BUG; 8547a7e6055SDimitry Andric ProgInfo.NumSGPRsForWavesPerEU = 8557a7e6055SDimitry Andric AMDGPU::IsaInfo::FIXED_NUM_SGPRS_FOR_INIT_BUG; 8568f0fd8f6SDimitry Andric } 8578f0fd8f6SDimitry Andric 8586bc11b14SDimitry Andric if (MFI->getNumUserSGPRs() > STM.getMaxNumUserSGPRs()) { 8592cab237bSDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 8602cab237bSDimitry Andric DiagnosticInfoResourceLimit Diag(MF.getFunction(), "user SGPRs", 8616bc11b14SDimitry Andric MFI->getNumUserSGPRs(), DS_Error); 8623ca95b02SDimitry Andric Ctx.diagnose(Diag); 8633ca95b02SDimitry Andric } 8643ca95b02SDimitry Andric 865d88c1a5aSDimitry Andric if (MFI->getLDSSize() > static_cast<unsigned>(STM.getLocalMemorySize())) { 8662cab237bSDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 8672cab237bSDimitry Andric DiagnosticInfoResourceLimit Diag(MF.getFunction(), "local memory", 868d88c1a5aSDimitry Andric MFI->getLDSSize(), DS_Error); 8693ca95b02SDimitry Andric Ctx.diagnose(Diag); 8707d523365SDimitry Andric } 8717d523365SDimitry Andric 872d88c1a5aSDimitry Andric // SGPRBlocks is actual number of SGPR blocks minus 1. 873d88c1a5aSDimitry Andric ProgInfo.SGPRBlocks = alignTo(ProgInfo.NumSGPRsForWavesPerEU, 8747a7e6055SDimitry Andric STM.getSGPREncodingGranule()); 8757a7e6055SDimitry Andric ProgInfo.SGPRBlocks = ProgInfo.SGPRBlocks / STM.getSGPREncodingGranule() - 1; 876d88c1a5aSDimitry Andric 877d88c1a5aSDimitry Andric // VGPRBlocks is actual number of VGPR blocks minus 1. 878d88c1a5aSDimitry Andric ProgInfo.VGPRBlocks = alignTo(ProgInfo.NumVGPRsForWavesPerEU, 8797a7e6055SDimitry Andric STM.getVGPREncodingGranule()); 8807a7e6055SDimitry Andric ProgInfo.VGPRBlocks = ProgInfo.VGPRBlocks / STM.getVGPREncodingGranule() - 1; 8817a7e6055SDimitry Andric 8827a7e6055SDimitry Andric // Record first reserved VGPR and number of reserved VGPRs. 8836bc11b14SDimitry Andric ProgInfo.ReservedVGPRFirst = STM.debuggerReserveRegs() ? ProgInfo.NumVGPR : 0; 8847a7e6055SDimitry Andric ProgInfo.ReservedVGPRCount = STM.getReservedNumVGPRs(MF); 8857a7e6055SDimitry Andric 8867a7e6055SDimitry Andric // Update DebuggerWavefrontPrivateSegmentOffsetSGPR and 8877a7e6055SDimitry Andric // DebuggerPrivateSegmentBufferSGPR fields if "amdgpu-debugger-emit-prologue" 8887a7e6055SDimitry Andric // attribute was requested. 8897a7e6055SDimitry Andric if (STM.debuggerEmitPrologue()) { 8907a7e6055SDimitry Andric ProgInfo.DebuggerWavefrontPrivateSegmentOffsetSGPR = 8917a7e6055SDimitry Andric RI->getHWRegIndex(MFI->getScratchWaveOffsetReg()); 8927a7e6055SDimitry Andric ProgInfo.DebuggerPrivateSegmentBufferSGPR = 8937a7e6055SDimitry Andric RI->getHWRegIndex(MFI->getScratchRSrcReg()); 8947a7e6055SDimitry Andric } 895d88c1a5aSDimitry Andric 8968f0fd8f6SDimitry Andric // Set the value to initialize FP_ROUND and FP_DENORM parts of the mode 8978f0fd8f6SDimitry Andric // register. 8988f0fd8f6SDimitry Andric ProgInfo.FloatMode = getFPMode(MF); 8998f0fd8f6SDimitry Andric 900d88c1a5aSDimitry Andric ProgInfo.IEEEMode = STM.enableIEEEBit(MF); 9018f0fd8f6SDimitry Andric 9023ca95b02SDimitry Andric // Make clamp modifier on NaN input returns 0. 9037a7e6055SDimitry Andric ProgInfo.DX10Clamp = STM.enableDX10Clamp(); 9048f0fd8f6SDimitry Andric 9058f0fd8f6SDimitry Andric unsigned LDSAlignShift; 9063ca95b02SDimitry Andric if (STM.getGeneration() < SISubtarget::SEA_ISLANDS) { 9078f0fd8f6SDimitry Andric // LDS is allocated in 64 dword blocks. 9088f0fd8f6SDimitry Andric LDSAlignShift = 8; 9098f0fd8f6SDimitry Andric } else { 9108f0fd8f6SDimitry Andric // LDS is allocated in 128 dword blocks. 9118f0fd8f6SDimitry Andric LDSAlignShift = 9; 9128f0fd8f6SDimitry Andric } 9138f0fd8f6SDimitry Andric 914d88c1a5aSDimitry Andric unsigned LDSSpillSize = 9156bc11b14SDimitry Andric MFI->getLDSWaveSpillSize() * MFI->getMaxFlatWorkGroupSize(); 9168f0fd8f6SDimitry Andric 917d88c1a5aSDimitry Andric ProgInfo.LDSSize = MFI->getLDSSize() + LDSSpillSize; 9188f0fd8f6SDimitry Andric ProgInfo.LDSBlocks = 9193ca95b02SDimitry Andric alignTo(ProgInfo.LDSSize, 1ULL << LDSAlignShift) >> LDSAlignShift; 9208f0fd8f6SDimitry Andric 9218f0fd8f6SDimitry Andric // Scratch is allocated in 256 dword blocks. 9228f0fd8f6SDimitry Andric unsigned ScratchAlignShift = 10; 9238f0fd8f6SDimitry Andric // We need to program the hardware with the amount of scratch memory that 9248f0fd8f6SDimitry Andric // is used by the entire wave. ProgInfo.ScratchSize is the amount of 9258f0fd8f6SDimitry Andric // scratch memory used per thread. 9268f0fd8f6SDimitry Andric ProgInfo.ScratchBlocks = 9273ca95b02SDimitry Andric alignTo(ProgInfo.ScratchSize * STM.getWavefrontSize(), 9283ca95b02SDimitry Andric 1ULL << ScratchAlignShift) >> 9293ca95b02SDimitry Andric ScratchAlignShift; 9308f0fd8f6SDimitry Andric 9318f0fd8f6SDimitry Andric ProgInfo.ComputePGMRSrc1 = 9328f0fd8f6SDimitry Andric S_00B848_VGPRS(ProgInfo.VGPRBlocks) | 9338f0fd8f6SDimitry Andric S_00B848_SGPRS(ProgInfo.SGPRBlocks) | 9348f0fd8f6SDimitry Andric S_00B848_PRIORITY(ProgInfo.Priority) | 9358f0fd8f6SDimitry Andric S_00B848_FLOAT_MODE(ProgInfo.FloatMode) | 9368f0fd8f6SDimitry Andric S_00B848_PRIV(ProgInfo.Priv) | 9378f0fd8f6SDimitry Andric S_00B848_DX10_CLAMP(ProgInfo.DX10Clamp) | 9387d523365SDimitry Andric S_00B848_DEBUG_MODE(ProgInfo.DebugMode) | 9398f0fd8f6SDimitry Andric S_00B848_IEEE_MODE(ProgInfo.IEEEMode); 9408f0fd8f6SDimitry Andric 9417d523365SDimitry Andric // 0 = X, 1 = XY, 2 = XYZ 9427d523365SDimitry Andric unsigned TIDIGCompCnt = 0; 9437d523365SDimitry Andric if (MFI->hasWorkItemIDZ()) 9447d523365SDimitry Andric TIDIGCompCnt = 2; 9457d523365SDimitry Andric else if (MFI->hasWorkItemIDY()) 9467d523365SDimitry Andric TIDIGCompCnt = 1; 9477d523365SDimitry Andric 9488f0fd8f6SDimitry Andric ProgInfo.ComputePGMRSrc2 = 9498f0fd8f6SDimitry Andric S_00B84C_SCRATCH_EN(ProgInfo.ScratchBlocks > 0) | 9507d523365SDimitry Andric S_00B84C_USER_SGPR(MFI->getNumUserSGPRs()) | 9517a7e6055SDimitry Andric S_00B84C_TRAP_HANDLER(STM.isTrapHandlerEnabled()) | 9527d523365SDimitry Andric S_00B84C_TGID_X_EN(MFI->hasWorkGroupIDX()) | 9537d523365SDimitry Andric S_00B84C_TGID_Y_EN(MFI->hasWorkGroupIDY()) | 9547d523365SDimitry Andric S_00B84C_TGID_Z_EN(MFI->hasWorkGroupIDZ()) | 9557d523365SDimitry Andric S_00B84C_TG_SIZE_EN(MFI->hasWorkGroupInfo()) | 9567d523365SDimitry Andric S_00B84C_TIDIG_COMP_CNT(TIDIGCompCnt) | 9577d523365SDimitry Andric S_00B84C_EXCP_EN_MSB(0) | 9580f5676f4SDimitry Andric // For AMDHSA, LDS_SIZE must be zero, as it is populated by the CP. 9590f5676f4SDimitry Andric S_00B84C_LDS_SIZE(STM.isAmdHsaOS() ? 0 : ProgInfo.LDSBlocks) | 9607d523365SDimitry Andric S_00B84C_EXCP_EN(0); 9618f0fd8f6SDimitry Andric } 9628f0fd8f6SDimitry Andric 9633ca95b02SDimitry Andric static unsigned getRsrcReg(CallingConv::ID CallConv) { 9643ca95b02SDimitry Andric switch (CallConv) { 965d88c1a5aSDimitry Andric default: LLVM_FALLTHROUGH; 9663ca95b02SDimitry Andric case CallingConv::AMDGPU_CS: return R_00B848_COMPUTE_PGM_RSRC1; 9672cab237bSDimitry Andric case CallingConv::AMDGPU_LS: return R_00B528_SPI_SHADER_PGM_RSRC1_LS; 968f37b6182SDimitry Andric case CallingConv::AMDGPU_HS: return R_00B428_SPI_SHADER_PGM_RSRC1_HS; 9692cab237bSDimitry Andric case CallingConv::AMDGPU_ES: return R_00B328_SPI_SHADER_PGM_RSRC1_ES; 9703ca95b02SDimitry Andric case CallingConv::AMDGPU_GS: return R_00B228_SPI_SHADER_PGM_RSRC1_GS; 9713ca95b02SDimitry Andric case CallingConv::AMDGPU_VS: return R_00B128_SPI_SHADER_PGM_RSRC1_VS; 9722cab237bSDimitry Andric case CallingConv::AMDGPU_PS: return R_00B028_SPI_SHADER_PGM_RSRC1_PS; 9738f0fd8f6SDimitry Andric } 9748f0fd8f6SDimitry Andric } 9758f0fd8f6SDimitry Andric 9768f0fd8f6SDimitry Andric void AMDGPUAsmPrinter::EmitProgramInfoSI(const MachineFunction &MF, 977f37b6182SDimitry Andric const SIProgramInfo &CurrentProgramInfo) { 9783ca95b02SDimitry Andric const SISubtarget &STM = MF.getSubtarget<SISubtarget>(); 9798f0fd8f6SDimitry Andric const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 9802cab237bSDimitry Andric unsigned RsrcReg = getRsrcReg(MF.getFunction().getCallingConv()); 9818f0fd8f6SDimitry Andric 9822cab237bSDimitry Andric if (AMDGPU::isCompute(MF.getFunction().getCallingConv())) { 9838f0fd8f6SDimitry Andric OutStreamer->EmitIntValue(R_00B848_COMPUTE_PGM_RSRC1, 4); 9848f0fd8f6SDimitry Andric 985f37b6182SDimitry Andric OutStreamer->EmitIntValue(CurrentProgramInfo.ComputePGMRSrc1, 4); 9868f0fd8f6SDimitry Andric 9878f0fd8f6SDimitry Andric OutStreamer->EmitIntValue(R_00B84C_COMPUTE_PGM_RSRC2, 4); 988f37b6182SDimitry Andric OutStreamer->EmitIntValue(CurrentProgramInfo.ComputePGMRSrc2, 4); 9898f0fd8f6SDimitry Andric 9908f0fd8f6SDimitry Andric OutStreamer->EmitIntValue(R_00B860_COMPUTE_TMPRING_SIZE, 4); 991f37b6182SDimitry Andric OutStreamer->EmitIntValue(S_00B860_WAVESIZE(CurrentProgramInfo.ScratchBlocks), 4); 9928f0fd8f6SDimitry Andric 9938f0fd8f6SDimitry Andric // TODO: Should probably note flat usage somewhere. SC emits a "FlatPtr32 = 9948f0fd8f6SDimitry Andric // 0" comment but I don't see a corresponding field in the register spec. 9958f0fd8f6SDimitry Andric } else { 9968f0fd8f6SDimitry Andric OutStreamer->EmitIntValue(RsrcReg, 4); 997f37b6182SDimitry Andric OutStreamer->EmitIntValue(S_00B028_VGPRS(CurrentProgramInfo.VGPRBlocks) | 998f37b6182SDimitry Andric S_00B028_SGPRS(CurrentProgramInfo.SGPRBlocks), 4); 9992cab237bSDimitry Andric unsigned Rsrc2Val = 0; 10002cab237bSDimitry Andric if (STM.isVGPRSpillingEnabled(MF.getFunction())) { 10018f0fd8f6SDimitry Andric OutStreamer->EmitIntValue(R_0286E8_SPI_TMPRING_SIZE, 4); 1002f37b6182SDimitry Andric OutStreamer->EmitIntValue(S_0286E8_WAVESIZE(CurrentProgramInfo.ScratchBlocks), 4); 10032cab237bSDimitry Andric if (TM.getTargetTriple().getOS() == Triple::AMDPAL) 10042cab237bSDimitry Andric Rsrc2Val = S_00B84C_SCRATCH_EN(CurrentProgramInfo.ScratchBlocks > 0); 10058f0fd8f6SDimitry Andric } 10062cab237bSDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::AMDGPU_PS) { 10078f0fd8f6SDimitry Andric OutStreamer->EmitIntValue(R_0286CC_SPI_PS_INPUT_ENA, 4); 10087a7e6055SDimitry Andric OutStreamer->EmitIntValue(MFI->getPSInputEnable(), 4); 1009444ed5c5SDimitry Andric OutStreamer->EmitIntValue(R_0286D0_SPI_PS_INPUT_ADDR, 4); 1010444ed5c5SDimitry Andric OutStreamer->EmitIntValue(MFI->getPSInputAddr(), 4); 10112cab237bSDimitry Andric Rsrc2Val |= S_00B02C_EXTRA_LDS_SIZE(CurrentProgramInfo.LDSBlocks); 10122cab237bSDimitry Andric } 10132cab237bSDimitry Andric if (Rsrc2Val) { 10142cab237bSDimitry Andric OutStreamer->EmitIntValue(RsrcReg + 4 /*rsrc2*/, 4); 10152cab237bSDimitry Andric OutStreamer->EmitIntValue(Rsrc2Val, 4); 10162cab237bSDimitry Andric } 10178f0fd8f6SDimitry Andric } 10183ca95b02SDimitry Andric 10193ca95b02SDimitry Andric OutStreamer->EmitIntValue(R_SPILLED_SGPRS, 4); 10203ca95b02SDimitry Andric OutStreamer->EmitIntValue(MFI->getNumSpilledSGPRs(), 4); 10213ca95b02SDimitry Andric OutStreamer->EmitIntValue(R_SPILLED_VGPRS, 4); 10223ca95b02SDimitry Andric OutStreamer->EmitIntValue(MFI->getNumSpilledVGPRs(), 4); 10233ca95b02SDimitry Andric } 10243ca95b02SDimitry Andric 10252cab237bSDimitry Andric // This is the equivalent of EmitProgramInfoSI above, but for when the OS type 10262cab237bSDimitry Andric // is AMDPAL. It stores each compute/SPI register setting and other PAL 10272cab237bSDimitry Andric // metadata items into the PALMetadataMap, combining with any provided by the 10282cab237bSDimitry Andric // frontend as LLVM metadata. Once all functions are written, PALMetadataMap is 10292cab237bSDimitry Andric // then written as a single block in the .note section. 10302cab237bSDimitry Andric void AMDGPUAsmPrinter::EmitPALMetadata(const MachineFunction &MF, 10312cab237bSDimitry Andric const SIProgramInfo &CurrentProgramInfo) { 10322cab237bSDimitry Andric const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 10332cab237bSDimitry Andric // Given the calling convention, calculate the register number for rsrc1. In 10342cab237bSDimitry Andric // principle the register number could change in future hardware, but we know 10352cab237bSDimitry Andric // it is the same for gfx6-9 (except that LS and ES don't exist on gfx9), so 10362cab237bSDimitry Andric // we can use the same fixed value that .AMDGPU.config has for Mesa. Note 10372cab237bSDimitry Andric // that we use a register number rather than a byte offset, so we need to 10382cab237bSDimitry Andric // divide by 4. 10392cab237bSDimitry Andric unsigned Rsrc1Reg = getRsrcReg(MF.getFunction().getCallingConv()) / 4; 10402cab237bSDimitry Andric unsigned Rsrc2Reg = Rsrc1Reg + 1; 10412cab237bSDimitry Andric // Also calculate the PAL metadata key for *S_SCRATCH_SIZE. It can be used 10422cab237bSDimitry Andric // with a constant offset to access any non-register shader-specific PAL 10432cab237bSDimitry Andric // metadata key. 10442cab237bSDimitry Andric unsigned ScratchSizeKey = PALMD::Key::CS_SCRATCH_SIZE; 10452cab237bSDimitry Andric switch (MF.getFunction().getCallingConv()) { 10462cab237bSDimitry Andric case CallingConv::AMDGPU_PS: 10472cab237bSDimitry Andric ScratchSizeKey = PALMD::Key::PS_SCRATCH_SIZE; 10482cab237bSDimitry Andric break; 10492cab237bSDimitry Andric case CallingConv::AMDGPU_VS: 10502cab237bSDimitry Andric ScratchSizeKey = PALMD::Key::VS_SCRATCH_SIZE; 10512cab237bSDimitry Andric break; 10522cab237bSDimitry Andric case CallingConv::AMDGPU_GS: 10532cab237bSDimitry Andric ScratchSizeKey = PALMD::Key::GS_SCRATCH_SIZE; 10542cab237bSDimitry Andric break; 10552cab237bSDimitry Andric case CallingConv::AMDGPU_ES: 10562cab237bSDimitry Andric ScratchSizeKey = PALMD::Key::ES_SCRATCH_SIZE; 10572cab237bSDimitry Andric break; 10582cab237bSDimitry Andric case CallingConv::AMDGPU_HS: 10592cab237bSDimitry Andric ScratchSizeKey = PALMD::Key::HS_SCRATCH_SIZE; 10602cab237bSDimitry Andric break; 10612cab237bSDimitry Andric case CallingConv::AMDGPU_LS: 10622cab237bSDimitry Andric ScratchSizeKey = PALMD::Key::LS_SCRATCH_SIZE; 10632cab237bSDimitry Andric break; 10642cab237bSDimitry Andric } 10652cab237bSDimitry Andric unsigned NumUsedVgprsKey = ScratchSizeKey + 10662cab237bSDimitry Andric PALMD::Key::VS_NUM_USED_VGPRS - PALMD::Key::VS_SCRATCH_SIZE; 10672cab237bSDimitry Andric unsigned NumUsedSgprsKey = ScratchSizeKey + 10682cab237bSDimitry Andric PALMD::Key::VS_NUM_USED_SGPRS - PALMD::Key::VS_SCRATCH_SIZE; 10692cab237bSDimitry Andric PALMetadataMap[NumUsedVgprsKey] = CurrentProgramInfo.NumVGPRsForWavesPerEU; 10702cab237bSDimitry Andric PALMetadataMap[NumUsedSgprsKey] = CurrentProgramInfo.NumSGPRsForWavesPerEU; 10712cab237bSDimitry Andric if (AMDGPU::isCompute(MF.getFunction().getCallingConv())) { 10722cab237bSDimitry Andric PALMetadataMap[Rsrc1Reg] |= CurrentProgramInfo.ComputePGMRSrc1; 10732cab237bSDimitry Andric PALMetadataMap[Rsrc2Reg] |= CurrentProgramInfo.ComputePGMRSrc2; 10742cab237bSDimitry Andric // ScratchSize is in bytes, 16 aligned. 10752cab237bSDimitry Andric PALMetadataMap[ScratchSizeKey] |= 10762cab237bSDimitry Andric alignTo(CurrentProgramInfo.ScratchSize, 16); 10772cab237bSDimitry Andric } else { 10782cab237bSDimitry Andric PALMetadataMap[Rsrc1Reg] |= S_00B028_VGPRS(CurrentProgramInfo.VGPRBlocks) | 10792cab237bSDimitry Andric S_00B028_SGPRS(CurrentProgramInfo.SGPRBlocks); 10802cab237bSDimitry Andric if (CurrentProgramInfo.ScratchBlocks > 0) 10812cab237bSDimitry Andric PALMetadataMap[Rsrc2Reg] |= S_00B84C_SCRATCH_EN(1); 10822cab237bSDimitry Andric // ScratchSize is in bytes, 16 aligned. 10832cab237bSDimitry Andric PALMetadataMap[ScratchSizeKey] |= 10842cab237bSDimitry Andric alignTo(CurrentProgramInfo.ScratchSize, 16); 10852cab237bSDimitry Andric } 10862cab237bSDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::AMDGPU_PS) { 10872cab237bSDimitry Andric PALMetadataMap[Rsrc2Reg] |= 10882cab237bSDimitry Andric S_00B02C_EXTRA_LDS_SIZE(CurrentProgramInfo.LDSBlocks); 10892cab237bSDimitry Andric PALMetadataMap[R_0286CC_SPI_PS_INPUT_ENA / 4] |= MFI->getPSInputEnable(); 10902cab237bSDimitry Andric PALMetadataMap[R_0286D0_SPI_PS_INPUT_ADDR / 4] |= MFI->getPSInputAddr(); 10912cab237bSDimitry Andric } 10922cab237bSDimitry Andric } 10932cab237bSDimitry Andric 10943ca95b02SDimitry Andric // This is supposed to be log2(Size) 10953ca95b02SDimitry Andric static amd_element_byte_size_t getElementByteSizeValue(unsigned Size) { 10963ca95b02SDimitry Andric switch (Size) { 10973ca95b02SDimitry Andric case 4: 10983ca95b02SDimitry Andric return AMD_ELEMENT_4_BYTES; 10993ca95b02SDimitry Andric case 8: 11003ca95b02SDimitry Andric return AMD_ELEMENT_8_BYTES; 11013ca95b02SDimitry Andric case 16: 11023ca95b02SDimitry Andric return AMD_ELEMENT_16_BYTES; 11033ca95b02SDimitry Andric default: 11043ca95b02SDimitry Andric llvm_unreachable("invalid private_element_size"); 11053ca95b02SDimitry Andric } 11068f0fd8f6SDimitry Andric } 11078f0fd8f6SDimitry Andric 11087a7e6055SDimitry Andric void AMDGPUAsmPrinter::getAmdKernelCode(amd_kernel_code_t &Out, 1109f37b6182SDimitry Andric const SIProgramInfo &CurrentProgramInfo, 11107a7e6055SDimitry Andric const MachineFunction &MF) const { 11118f0fd8f6SDimitry Andric const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 11123ca95b02SDimitry Andric const SISubtarget &STM = MF.getSubtarget<SISubtarget>(); 11138f0fd8f6SDimitry Andric 11147a7e6055SDimitry Andric AMDGPU::initDefaultAMDKernelCodeT(Out, STM.getFeatureBits()); 11158f0fd8f6SDimitry Andric 11167a7e6055SDimitry Andric Out.compute_pgm_resource_registers = 1117f37b6182SDimitry Andric CurrentProgramInfo.ComputePGMRSrc1 | 1118f37b6182SDimitry Andric (CurrentProgramInfo.ComputePGMRSrc2 << 32); 11197a7e6055SDimitry Andric Out.code_properties = AMD_CODE_PROPERTY_IS_PTR64; 11207d523365SDimitry Andric 1121f37b6182SDimitry Andric if (CurrentProgramInfo.DynamicCallStack) 1122f37b6182SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_IS_DYNAMIC_CALLSTACK; 1123f37b6182SDimitry Andric 11247a7e6055SDimitry Andric AMD_HSA_BITS_SET(Out.code_properties, 11253ca95b02SDimitry Andric AMD_CODE_PROPERTY_PRIVATE_ELEMENT_SIZE, 11263ca95b02SDimitry Andric getElementByteSizeValue(STM.getMaxPrivateElementSize())); 11273ca95b02SDimitry Andric 11287d523365SDimitry Andric if (MFI->hasPrivateSegmentBuffer()) { 11297a7e6055SDimitry Andric Out.code_properties |= 11307d523365SDimitry Andric AMD_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER; 11317d523365SDimitry Andric } 11327d523365SDimitry Andric 11337d523365SDimitry Andric if (MFI->hasDispatchPtr()) 11347a7e6055SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_PTR; 11357d523365SDimitry Andric 11367d523365SDimitry Andric if (MFI->hasQueuePtr()) 11377a7e6055SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_QUEUE_PTR; 11387d523365SDimitry Andric 11397d523365SDimitry Andric if (MFI->hasKernargSegmentPtr()) 11407a7e6055SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_KERNARG_SEGMENT_PTR; 11417d523365SDimitry Andric 11427d523365SDimitry Andric if (MFI->hasDispatchID()) 11437a7e6055SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_ID; 11447d523365SDimitry Andric 11457d523365SDimitry Andric if (MFI->hasFlatScratchInit()) 11467a7e6055SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_FLAT_SCRATCH_INIT; 11477d523365SDimitry Andric 11487d523365SDimitry Andric if (MFI->hasGridWorkgroupCountX()) { 11497a7e6055SDimitry Andric Out.code_properties |= 11507d523365SDimitry Andric AMD_CODE_PROPERTY_ENABLE_SGPR_GRID_WORKGROUP_COUNT_X; 11517d523365SDimitry Andric } 11527d523365SDimitry Andric 11537d523365SDimitry Andric if (MFI->hasGridWorkgroupCountY()) { 11547a7e6055SDimitry Andric Out.code_properties |= 11557d523365SDimitry Andric AMD_CODE_PROPERTY_ENABLE_SGPR_GRID_WORKGROUP_COUNT_Y; 11567d523365SDimitry Andric } 11577d523365SDimitry Andric 11587d523365SDimitry Andric if (MFI->hasGridWorkgroupCountZ()) { 11597a7e6055SDimitry Andric Out.code_properties |= 11607d523365SDimitry Andric AMD_CODE_PROPERTY_ENABLE_SGPR_GRID_WORKGROUP_COUNT_Z; 11617d523365SDimitry Andric } 11627d523365SDimitry Andric 11637d523365SDimitry Andric if (MFI->hasDispatchPtr()) 11647a7e6055SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_PTR; 11658f0fd8f6SDimitry Andric 11663ca95b02SDimitry Andric if (STM.debuggerSupported()) 11677a7e6055SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_IS_DEBUG_SUPPORTED; 11683ca95b02SDimitry Andric 11694d0b32cdSDimitry Andric if (STM.isXNACKEnabled()) 11707a7e6055SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_IS_XNACK_SUPPORTED; 11714d0b32cdSDimitry Andric 1172d88c1a5aSDimitry Andric // FIXME: Should use getKernArgSize 11737a7e6055SDimitry Andric Out.kernarg_segment_byte_size = 117498221d2eSDimitry Andric STM.getKernArgSegmentSize(MF, MFI->getABIArgOffset()); 1175f37b6182SDimitry Andric Out.wavefront_sgpr_count = CurrentProgramInfo.NumSGPR; 1176f37b6182SDimitry Andric Out.workitem_vgpr_count = CurrentProgramInfo.NumVGPR; 1177f37b6182SDimitry Andric Out.workitem_private_segment_byte_size = CurrentProgramInfo.ScratchSize; 1178f37b6182SDimitry Andric Out.workgroup_group_segment_byte_size = CurrentProgramInfo.LDSSize; 1179f37b6182SDimitry Andric Out.reserved_vgpr_first = CurrentProgramInfo.ReservedVGPRFirst; 1180f37b6182SDimitry Andric Out.reserved_vgpr_count = CurrentProgramInfo.ReservedVGPRCount; 11813ca95b02SDimitry Andric 1182d88c1a5aSDimitry Andric // These alignment values are specified in powers of two, so alignment = 1183d88c1a5aSDimitry Andric // 2^n. The minimum alignment is 2^4 = 16. 11847a7e6055SDimitry Andric Out.kernarg_segment_alignment = std::max((size_t)4, 1185d88c1a5aSDimitry Andric countTrailingZeros(MFI->getMaxKernArgAlign())); 1186d88c1a5aSDimitry Andric 11873ca95b02SDimitry Andric if (STM.debuggerEmitPrologue()) { 11887a7e6055SDimitry Andric Out.debug_wavefront_private_segment_offset_sgpr = 1189f37b6182SDimitry Andric CurrentProgramInfo.DebuggerWavefrontPrivateSegmentOffsetSGPR; 11907a7e6055SDimitry Andric Out.debug_private_segment_buffer_sgpr = 1191f37b6182SDimitry Andric CurrentProgramInfo.DebuggerPrivateSegmentBufferSGPR; 11923ca95b02SDimitry Andric } 11938f0fd8f6SDimitry Andric } 11948f0fd8f6SDimitry Andric 11952cab237bSDimitry Andric AMDGPU::HSAMD::Kernel::CodeProps::Metadata AMDGPUAsmPrinter::getHSACodeProps( 11962cab237bSDimitry Andric const MachineFunction &MF, 11972cab237bSDimitry Andric const SIProgramInfo &ProgramInfo) const { 11982cab237bSDimitry Andric const SISubtarget &STM = MF.getSubtarget<SISubtarget>(); 11992cab237bSDimitry Andric const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>(); 12002cab237bSDimitry Andric HSAMD::Kernel::CodeProps::Metadata HSACodeProps; 12012cab237bSDimitry Andric 12022cab237bSDimitry Andric HSACodeProps.mKernargSegmentSize = 12032cab237bSDimitry Andric STM.getKernArgSegmentSize(MF, MFI.getABIArgOffset()); 12042cab237bSDimitry Andric HSACodeProps.mGroupSegmentFixedSize = ProgramInfo.LDSSize; 12052cab237bSDimitry Andric HSACodeProps.mPrivateSegmentFixedSize = ProgramInfo.ScratchSize; 12062cab237bSDimitry Andric HSACodeProps.mKernargSegmentAlign = 12072cab237bSDimitry Andric std::max(uint32_t(4), MFI.getMaxKernArgAlign()); 12082cab237bSDimitry Andric HSACodeProps.mWavefrontSize = STM.getWavefrontSize(); 12092cab237bSDimitry Andric HSACodeProps.mNumSGPRs = CurrentProgramInfo.NumSGPR; 12102cab237bSDimitry Andric HSACodeProps.mNumVGPRs = CurrentProgramInfo.NumVGPR; 12112cab237bSDimitry Andric HSACodeProps.mMaxFlatWorkGroupSize = MFI.getMaxFlatWorkGroupSize(); 12122cab237bSDimitry Andric HSACodeProps.mIsDynamicCallStack = ProgramInfo.DynamicCallStack; 12132cab237bSDimitry Andric HSACodeProps.mIsXNACKEnabled = STM.isXNACKEnabled(); 12142cab237bSDimitry Andric HSACodeProps.mNumSpilledSGPRs = MFI.getNumSpilledSGPRs(); 12152cab237bSDimitry Andric HSACodeProps.mNumSpilledVGPRs = MFI.getNumSpilledVGPRs(); 12162cab237bSDimitry Andric 12172cab237bSDimitry Andric return HSACodeProps; 12182cab237bSDimitry Andric } 12192cab237bSDimitry Andric 12202cab237bSDimitry Andric AMDGPU::HSAMD::Kernel::DebugProps::Metadata AMDGPUAsmPrinter::getHSADebugProps( 12212cab237bSDimitry Andric const MachineFunction &MF, 12222cab237bSDimitry Andric const SIProgramInfo &ProgramInfo) const { 12232cab237bSDimitry Andric const SISubtarget &STM = MF.getSubtarget<SISubtarget>(); 12242cab237bSDimitry Andric HSAMD::Kernel::DebugProps::Metadata HSADebugProps; 12252cab237bSDimitry Andric 12262cab237bSDimitry Andric if (!STM.debuggerSupported()) 12272cab237bSDimitry Andric return HSADebugProps; 12282cab237bSDimitry Andric 12292cab237bSDimitry Andric HSADebugProps.mDebuggerABIVersion.push_back(1); 12302cab237bSDimitry Andric HSADebugProps.mDebuggerABIVersion.push_back(0); 12312cab237bSDimitry Andric HSADebugProps.mReservedNumVGPRs = ProgramInfo.ReservedVGPRCount; 12322cab237bSDimitry Andric HSADebugProps.mReservedFirstVGPR = ProgramInfo.ReservedVGPRFirst; 12332cab237bSDimitry Andric 12342cab237bSDimitry Andric if (STM.debuggerEmitPrologue()) { 12352cab237bSDimitry Andric HSADebugProps.mPrivateSegmentBufferSGPR = 12362cab237bSDimitry Andric ProgramInfo.DebuggerPrivateSegmentBufferSGPR; 12372cab237bSDimitry Andric HSADebugProps.mWavefrontPrivateSegmentOffsetSGPR = 12382cab237bSDimitry Andric ProgramInfo.DebuggerWavefrontPrivateSegmentOffsetSGPR; 12392cab237bSDimitry Andric } 12402cab237bSDimitry Andric 12412cab237bSDimitry Andric return HSADebugProps; 12422cab237bSDimitry Andric } 12432cab237bSDimitry Andric 12448f0fd8f6SDimitry Andric bool AMDGPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 12458f0fd8f6SDimitry Andric unsigned AsmVariant, 12468f0fd8f6SDimitry Andric const char *ExtraCode, raw_ostream &O) { 12472cab237bSDimitry Andric // First try the generic code, which knows about modifiers like 'c' and 'n'. 12482cab237bSDimitry Andric if (!AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O)) 12492cab237bSDimitry Andric return false; 12502cab237bSDimitry Andric 12518f0fd8f6SDimitry Andric if (ExtraCode && ExtraCode[0]) { 12528f0fd8f6SDimitry Andric if (ExtraCode[1] != 0) 12538f0fd8f6SDimitry Andric return true; // Unknown modifier. 12548f0fd8f6SDimitry Andric 12558f0fd8f6SDimitry Andric switch (ExtraCode[0]) { 12568f0fd8f6SDimitry Andric case 'r': 12578f0fd8f6SDimitry Andric break; 12582cab237bSDimitry Andric default: 12592cab237bSDimitry Andric return true; 12608f0fd8f6SDimitry Andric } 12618f0fd8f6SDimitry Andric } 12628f0fd8f6SDimitry Andric 12632cab237bSDimitry Andric // TODO: Should be able to support other operand types like globals. 12642cab237bSDimitry Andric const MachineOperand &MO = MI->getOperand(OpNo); 12652cab237bSDimitry Andric if (MO.isReg()) { 12662cab237bSDimitry Andric AMDGPUInstPrinter::printRegOperand(MO.getReg(), O, 12672cab237bSDimitry Andric *MF->getSubtarget().getRegisterInfo()); 12688f0fd8f6SDimitry Andric return false; 12698f0fd8f6SDimitry Andric } 12702cab237bSDimitry Andric 12712cab237bSDimitry Andric return true; 12722cab237bSDimitry Andric } 1273