1480093f4SDimitry Andric //===-- AMDGPUAsmPrinter.cpp - AMDGPU assembly printer --------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// 110b57cec5SDimitry Andric /// The AMDGPUAsmPrinter is used to print both assembly string and also binary 120b57cec5SDimitry Andric /// code. When passed an MCAsmStreamer it prints assembly and when passed 130b57cec5SDimitry Andric /// an MCObjectStreamer it outputs binary code. 140b57cec5SDimitry Andric // 150b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 160b57cec5SDimitry Andric // 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #include "AMDGPUAsmPrinter.h" 190b57cec5SDimitry Andric #include "AMDGPU.h" 20e8d8bef9SDimitry Andric #include "AMDGPUHSAMetadataStreamer.h" 21fe6060f1SDimitry Andric #include "AMDGPUResourceUsageAnalysis.h" 22e8d8bef9SDimitry Andric #include "GCNSubtarget.h" 230b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUInstPrinter.h" 24*0fca6ea1SDimitry Andric #include "MCTargetDesc/AMDGPUMCExpr.h" 25*0fca6ea1SDimitry Andric #include "MCTargetDesc/AMDGPUMCKernelDescriptor.h" 260b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUTargetStreamer.h" 270b57cec5SDimitry Andric #include "R600AsmPrinter.h" 280b57cec5SDimitry Andric #include "SIMachineFunctionInfo.h" 290b57cec5SDimitry Andric #include "TargetInfo/AMDGPUTargetInfo.h" 300b57cec5SDimitry Andric #include "Utils/AMDGPUBaseInfo.h" 31*0fca6ea1SDimitry Andric #include "Utils/AMDKernelCodeTUtils.h" 32*0fca6ea1SDimitry Andric #include "Utils/SIDefinesUtils.h" 33fcaf7f86SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h" 3481ad6265SDimitry Andric #include "llvm/BinaryFormat/ELF.h" 3581ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 36fcaf7f86SDimitry Andric #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" 370b57cec5SDimitry Andric #include "llvm/IR/DiagnosticInfo.h" 380b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h" 390b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 400b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h" 410b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 42349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h" 43e8d8bef9SDimitry Andric #include "llvm/Support/AMDHSAKernelDescriptor.h" 440b57cec5SDimitry Andric #include "llvm/Target/TargetLoweringObjectFile.h" 45e8d8bef9SDimitry Andric #include "llvm/Target/TargetMachine.h" 4606c3fb27SDimitry Andric #include "llvm/TargetParser/TargetParser.h" 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric using namespace llvm; 490b57cec5SDimitry Andric using namespace llvm::AMDGPU; 500b57cec5SDimitry Andric 515ffd83dbSDimitry Andric // This should get the default rounding mode from the kernel. We just set the 525ffd83dbSDimitry Andric // default here, but this could change if the OpenCL rounding mode pragmas are 535ffd83dbSDimitry Andric // used. 540b57cec5SDimitry Andric // 550b57cec5SDimitry Andric // The denormal mode here should match what is reported by the OpenCL runtime 560b57cec5SDimitry Andric // for the CL_FP_DENORM bit from CL_DEVICE_{HALF|SINGLE|DOUBLE}_FP_CONFIG, but 570b57cec5SDimitry Andric // can also be override to flush with the -cl-denorms-are-zero compiler flag. 580b57cec5SDimitry Andric // 590b57cec5SDimitry Andric // AMD OpenCL only sets flush none and reports CL_FP_DENORM for double 600b57cec5SDimitry Andric // precision, and leaves single precision to flush all and does not report 610b57cec5SDimitry Andric // CL_FP_DENORM for CL_DEVICE_SINGLE_FP_CONFIG. Mesa's OpenCL currently reports 620b57cec5SDimitry Andric // CL_FP_DENORM for both. 630b57cec5SDimitry Andric // 640b57cec5SDimitry Andric // FIXME: It seems some instructions do not support single precision denormals 650b57cec5SDimitry Andric // regardless of the mode (exp_*_f32, rcp_*_f32, rsq_*_f32, rsq_*f32, sqrt_f32, 660b57cec5SDimitry Andric // and sin_f32, cos_f32 on most parts). 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric // We want to use these instructions, and using fp32 denormals also causes 690b57cec5SDimitry Andric // instructions to run at the double precision rate for the device so it's 700b57cec5SDimitry Andric // probably best to just report no single precision denormals. 7106c3fb27SDimitry Andric static uint32_t getFPMode(SIModeRegisterDefaults Mode) { 720b57cec5SDimitry Andric return FP_ROUND_MODE_SP(FP_ROUND_ROUND_TO_NEAREST) | 730b57cec5SDimitry Andric FP_ROUND_MODE_DP(FP_ROUND_ROUND_TO_NEAREST) | 745ffd83dbSDimitry Andric FP_DENORM_MODE_SP(Mode.fpDenormModeSPValue()) | 755ffd83dbSDimitry Andric FP_DENORM_MODE_DP(Mode.fpDenormModeDPValue()); 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric static AsmPrinter * 790b57cec5SDimitry Andric createAMDGPUAsmPrinterPass(TargetMachine &tm, 800b57cec5SDimitry Andric std::unique_ptr<MCStreamer> &&Streamer) { 810b57cec5SDimitry Andric return new AMDGPUAsmPrinter(tm, std::move(Streamer)); 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric 8406c3fb27SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAMDGPUAsmPrinter() { 8506c3fb27SDimitry Andric TargetRegistry::RegisterAsmPrinter(getTheR600Target(), 860b57cec5SDimitry Andric llvm::createR600AsmPrinterPass); 870b57cec5SDimitry Andric TargetRegistry::RegisterAsmPrinter(getTheGCNTarget(), 880b57cec5SDimitry Andric createAMDGPUAsmPrinterPass); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric AMDGPUAsmPrinter::AMDGPUAsmPrinter(TargetMachine &TM, 920b57cec5SDimitry Andric std::unique_ptr<MCStreamer> Streamer) 930b57cec5SDimitry Andric : AsmPrinter(TM, std::move(Streamer)) { 94bdd1243dSDimitry Andric assert(OutStreamer && "AsmPrinter constructed without streamer"); 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric StringRef AMDGPUAsmPrinter::getPassName() const { 980b57cec5SDimitry Andric return "AMDGPU Assembly Printer"; 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric const MCSubtargetInfo *AMDGPUAsmPrinter::getGlobalSTI() const { 1020b57cec5SDimitry Andric return TM.getMCSubtargetInfo(); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric AMDGPUTargetStreamer* AMDGPUAsmPrinter::getTargetStreamer() const { 1060b57cec5SDimitry Andric if (!OutStreamer) 1070b57cec5SDimitry Andric return nullptr; 1080b57cec5SDimitry Andric return static_cast<AMDGPUTargetStreamer*>(OutStreamer->getTargetStreamer()); 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric 1115ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitStartOfAsmFile(Module &M) { 11281ad6265SDimitry Andric IsTargetStreamerInitialized = false; 11381ad6265SDimitry Andric } 11481ad6265SDimitry Andric 11581ad6265SDimitry Andric void AMDGPUAsmPrinter::initTargetStreamer(Module &M) { 11681ad6265SDimitry Andric IsTargetStreamerInitialized = true; 11781ad6265SDimitry Andric 118fe6060f1SDimitry Andric // TODO: Which one is called first, emitStartOfAsmFile or 119fe6060f1SDimitry Andric // emitFunctionBodyStart? 120fe6060f1SDimitry Andric if (getTargetStreamer() && !getTargetStreamer()->getTargetID()) 121fe6060f1SDimitry Andric initializeTargetID(M); 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric if (TM.getTargetTriple().getOS() != Triple::AMDHSA && 1240b57cec5SDimitry Andric TM.getTargetTriple().getOS() != Triple::AMDPAL) 1250b57cec5SDimitry Andric return; 1260b57cec5SDimitry Andric 127fe6060f1SDimitry Andric getTargetStreamer()->EmitDirectiveAMDGCNTarget(); 128fe6060f1SDimitry Andric 1297a6dacacSDimitry Andric if (TM.getTargetTriple().getOS() == Triple::AMDHSA) { 1307a6dacacSDimitry Andric getTargetStreamer()->EmitDirectiveAMDHSACodeObjectVersion( 1317a6dacacSDimitry Andric CodeObjectVersion); 132fe6060f1SDimitry Andric HSAMetadataStream->begin(M, *getTargetStreamer()->getTargetID()); 1337a6dacacSDimitry Andric } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric if (TM.getTargetTriple().getOS() == Triple::AMDPAL) 1360b57cec5SDimitry Andric getTargetStreamer()->getPALMetadata()->readFromIR(M); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1395ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitEndOfAsmFile(Module &M) { 14081ad6265SDimitry Andric // Init target streamer if it has not yet happened 14181ad6265SDimitry Andric if (!IsTargetStreamerInitialized) 14281ad6265SDimitry Andric initTargetStreamer(M); 14381ad6265SDimitry Andric 1445f757f3fSDimitry Andric if (TM.getTargetTriple().getOS() != Triple::AMDHSA) 145fe6060f1SDimitry Andric getTargetStreamer()->EmitISAVersion(); 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric // Emit HSA Metadata (NT_AMD_AMDGPU_HSA_METADATA). 148fe6060f1SDimitry Andric // Emit HSA Metadata (NT_AMD_HSA_METADATA). 1490b57cec5SDimitry Andric if (TM.getTargetTriple().getOS() == Triple::AMDHSA) { 1500b57cec5SDimitry Andric HSAMetadataStream->end(); 1510b57cec5SDimitry Andric bool Success = HSAMetadataStream->emitTo(*getTargetStreamer()); 1520b57cec5SDimitry Andric (void)Success; 1530b57cec5SDimitry Andric assert(Success && "Malformed HSA Metadata"); 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric 1575ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitFunctionBodyStart() { 1580b57cec5SDimitry Andric const SIMachineFunctionInfo &MFI = *MF->getInfo<SIMachineFunctionInfo>(); 159fe6060f1SDimitry Andric const GCNSubtarget &STM = MF->getSubtarget<GCNSubtarget>(); 160fe6060f1SDimitry Andric const Function &F = MF->getFunction(); 161fe6060f1SDimitry Andric 162*0fca6ea1SDimitry Andric // TODO: We're checking this late, would be nice to check it earlier. 163*0fca6ea1SDimitry Andric if (STM.requiresCodeObjectV6() && CodeObjectVersion < AMDGPU::AMDHSA_COV6) { 164*0fca6ea1SDimitry Andric report_fatal_error( 165*0fca6ea1SDimitry Andric STM.getCPU() + " is only available on code object version 6 or better", 166*0fca6ea1SDimitry Andric /*gen_crash_diag*/ false); 167*0fca6ea1SDimitry Andric } 168*0fca6ea1SDimitry Andric 169fe6060f1SDimitry Andric // TODO: Which one is called first, emitStartOfAsmFile or 170fe6060f1SDimitry Andric // emitFunctionBodyStart? 171bdd1243dSDimitry Andric if (!getTargetStreamer()->getTargetID()) 172fe6060f1SDimitry Andric initializeTargetID(*F.getParent()); 173fe6060f1SDimitry Andric 174fe6060f1SDimitry Andric const auto &FunctionTargetID = STM.getTargetID(); 175fe6060f1SDimitry Andric // Make sure function's xnack settings are compatible with module's 176fe6060f1SDimitry Andric // xnack settings. 177fe6060f1SDimitry Andric if (FunctionTargetID.isXnackSupported() && 178fe6060f1SDimitry Andric FunctionTargetID.getXnackSetting() != IsaInfo::TargetIDSetting::Any && 179fe6060f1SDimitry Andric FunctionTargetID.getXnackSetting() != getTargetStreamer()->getTargetID()->getXnackSetting()) { 180fe6060f1SDimitry Andric OutContext.reportError({}, "xnack setting of '" + Twine(MF->getName()) + 181fe6060f1SDimitry Andric "' function does not match module xnack setting"); 182fe6060f1SDimitry Andric return; 183fe6060f1SDimitry Andric } 184fe6060f1SDimitry Andric // Make sure function's sramecc settings are compatible with module's 185fe6060f1SDimitry Andric // sramecc settings. 186fe6060f1SDimitry Andric if (FunctionTargetID.isSramEccSupported() && 187fe6060f1SDimitry Andric FunctionTargetID.getSramEccSetting() != IsaInfo::TargetIDSetting::Any && 188fe6060f1SDimitry Andric FunctionTargetID.getSramEccSetting() != getTargetStreamer()->getTargetID()->getSramEccSetting()) { 189fe6060f1SDimitry Andric OutContext.reportError({}, "sramecc setting of '" + Twine(MF->getName()) + 190fe6060f1SDimitry Andric "' function does not match module sramecc setting"); 191fe6060f1SDimitry Andric return; 192fe6060f1SDimitry Andric } 193fe6060f1SDimitry Andric 1940b57cec5SDimitry Andric if (!MFI.isEntryFunction()) 1950b57cec5SDimitry Andric return; 1960b57cec5SDimitry Andric 1975f757f3fSDimitry Andric if (STM.isMesaKernel(F) && 1980b57cec5SDimitry Andric (F.getCallingConv() == CallingConv::AMDGPU_KERNEL || 1990b57cec5SDimitry Andric F.getCallingConv() == CallingConv::SPIR_KERNEL)) { 200*0fca6ea1SDimitry Andric AMDGPUMCKernelCodeT KernelCode; 2010b57cec5SDimitry Andric getAmdKernelCode(KernelCode, CurrentProgramInfo, *MF); 202*0fca6ea1SDimitry Andric KernelCode.validate(&STM, MF->getContext()); 2030b57cec5SDimitry Andric getTargetStreamer()->EmitAMDKernelCodeT(KernelCode); 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric if (STM.isAmdHsaOS()) 2070b57cec5SDimitry Andric HSAMetadataStream->emitKernel(*MF, CurrentProgramInfo); 2085f757f3fSDimitry Andric 2095f757f3fSDimitry Andric if (MFI.getNumKernargPreloadedSGPRs() > 0) { 2105f757f3fSDimitry Andric assert(AMDGPU::hasKernargPreload(STM)); 211*0fca6ea1SDimitry Andric getTargetStreamer()->EmitKernargPreloadHeader(*getGlobalSTI(), 212*0fca6ea1SDimitry Andric STM.isAmdHsaOS()); 2135f757f3fSDimitry Andric } 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 2165ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitFunctionBodyEnd() { 2170b57cec5SDimitry Andric const SIMachineFunctionInfo &MFI = *MF->getInfo<SIMachineFunctionInfo>(); 2180b57cec5SDimitry Andric if (!MFI.isEntryFunction()) 2190b57cec5SDimitry Andric return; 2200b57cec5SDimitry Andric 2215f757f3fSDimitry Andric if (TM.getTargetTriple().getOS() != Triple::AMDHSA) 2220b57cec5SDimitry Andric return; 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric auto &Streamer = getTargetStreamer()->getStreamer(); 2250b57cec5SDimitry Andric auto &Context = Streamer.getContext(); 2260b57cec5SDimitry Andric auto &ObjectFileInfo = *Context.getObjectFileInfo(); 2270b57cec5SDimitry Andric auto &ReadOnlySection = *ObjectFileInfo.getReadOnlySection(); 2280b57cec5SDimitry Andric 22981ad6265SDimitry Andric Streamer.pushSection(); 23081ad6265SDimitry Andric Streamer.switchSection(&ReadOnlySection); 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric // CP microcode requires the kernel descriptor to be allocated on 64 byte 2330b57cec5SDimitry Andric // alignment. 234bdd1243dSDimitry Andric Streamer.emitValueToAlignment(Align(64), 0, 1, 0); 235bdd1243dSDimitry Andric ReadOnlySection.ensureMinAlignment(Align(64)); 2360b57cec5SDimitry Andric 237fe6060f1SDimitry Andric const GCNSubtarget &STM = MF->getSubtarget<GCNSubtarget>(); 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric SmallString<128> KernelName; 2400b57cec5SDimitry Andric getNameWithPrefix(KernelName, &MF->getFunction()); 2410b57cec5SDimitry Andric getTargetStreamer()->EmitAmdhsaKernelDescriptor( 242fe6060f1SDimitry Andric STM, KernelName, getAmdhsaKernelDescriptor(*MF, CurrentProgramInfo), 2430b57cec5SDimitry Andric CurrentProgramInfo.NumVGPRsForWavesPerEU, 244*0fca6ea1SDimitry Andric MCBinaryExpr::createSub( 245*0fca6ea1SDimitry Andric CurrentProgramInfo.NumSGPRsForWavesPerEU, 246*0fca6ea1SDimitry Andric AMDGPUMCExpr::createExtraSGPRs( 247*0fca6ea1SDimitry Andric CurrentProgramInfo.VCCUsed, CurrentProgramInfo.FlatUsed, 248*0fca6ea1SDimitry Andric getTargetStreamer()->getTargetID()->isXnackOnOrAny(), Context), 249*0fca6ea1SDimitry Andric Context), 2507a6dacacSDimitry Andric CurrentProgramInfo.VCCUsed, CurrentProgramInfo.FlatUsed); 2510b57cec5SDimitry Andric 25281ad6265SDimitry Andric Streamer.popSection(); 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric 2555f757f3fSDimitry Andric void AMDGPUAsmPrinter::emitImplicitDef(const MachineInstr *MI) const { 2565f757f3fSDimitry Andric Register RegNo = MI->getOperand(0).getReg(); 2575f757f3fSDimitry Andric 2585f757f3fSDimitry Andric SmallString<128> Str; 2595f757f3fSDimitry Andric raw_svector_ostream OS(Str); 2605f757f3fSDimitry Andric OS << "implicit-def: " 2615f757f3fSDimitry Andric << printReg(RegNo, MF->getSubtarget().getRegisterInfo()); 2625f757f3fSDimitry Andric 2635f757f3fSDimitry Andric if (MI->getAsmPrinterFlags() & AMDGPU::SGPR_SPILL) 2645f757f3fSDimitry Andric OS << " : SGPR spill to VGPR lane"; 2655f757f3fSDimitry Andric 2665f757f3fSDimitry Andric OutStreamer->AddComment(OS.str()); 2675f757f3fSDimitry Andric OutStreamer->addBlankLine(); 2685f757f3fSDimitry Andric } 2695f757f3fSDimitry Andric 2705ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitFunctionEntryLabel() { 2715f757f3fSDimitry Andric if (TM.getTargetTriple().getOS() == Triple::AMDHSA) { 2725ffd83dbSDimitry Andric AsmPrinter::emitFunctionEntryLabel(); 2730b57cec5SDimitry Andric return; 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric const SIMachineFunctionInfo *MFI = MF->getInfo<SIMachineFunctionInfo>(); 2770b57cec5SDimitry Andric const GCNSubtarget &STM = MF->getSubtarget<GCNSubtarget>(); 2780b57cec5SDimitry Andric if (MFI->isEntryFunction() && STM.isAmdHsaOrMesa(MF->getFunction())) { 2790b57cec5SDimitry Andric SmallString<128> SymbolName; 2800b57cec5SDimitry Andric getNameWithPrefix(SymbolName, &MF->getFunction()), 2810b57cec5SDimitry Andric getTargetStreamer()->EmitAMDGPUSymbolType( 2820b57cec5SDimitry Andric SymbolName, ELF::STT_AMDGPU_HSA_KERNEL); 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric if (DumpCodeInstEmitter) { 2850b57cec5SDimitry Andric // Disassemble function name label to text. 2860b57cec5SDimitry Andric DisasmLines.push_back(MF->getName().str() + ":"); 2870b57cec5SDimitry Andric DisasmLineMaxLen = std::max(DisasmLineMaxLen, DisasmLines.back().size()); 288*0fca6ea1SDimitry Andric HexLines.emplace_back(""); 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric 2915ffd83dbSDimitry Andric AsmPrinter::emitFunctionEntryLabel(); 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric 2945ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) { 2950b57cec5SDimitry Andric if (DumpCodeInstEmitter && !isBlockOnlyReachableByFallthrough(&MBB)) { 2960b57cec5SDimitry Andric // Write a line for the basic block label if it is not only fallthrough. 2970b57cec5SDimitry Andric DisasmLines.push_back( 2980b57cec5SDimitry Andric (Twine("BB") + Twine(getFunctionNumber()) 2990b57cec5SDimitry Andric + "_" + Twine(MBB.getNumber()) + ":").str()); 3000b57cec5SDimitry Andric DisasmLineMaxLen = std::max(DisasmLineMaxLen, DisasmLines.back().size()); 301*0fca6ea1SDimitry Andric HexLines.emplace_back(""); 3020b57cec5SDimitry Andric } 3035ffd83dbSDimitry Andric AsmPrinter::emitBasicBlockStart(MBB); 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric 3065ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { 3070b57cec5SDimitry Andric if (GV->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) { 3080b57cec5SDimitry Andric if (GV->hasInitializer() && !isa<UndefValue>(GV->getInitializer())) { 3090b57cec5SDimitry Andric OutContext.reportError({}, 3100b57cec5SDimitry Andric Twine(GV->getName()) + 3110b57cec5SDimitry Andric ": unsupported initializer for address space"); 3120b57cec5SDimitry Andric return; 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric // LDS variables aren't emitted in HSA or PAL yet. 3160b57cec5SDimitry Andric const Triple::OSType OS = TM.getTargetTriple().getOS(); 3170b57cec5SDimitry Andric if (OS == Triple::AMDHSA || OS == Triple::AMDPAL) 3180b57cec5SDimitry Andric return; 3190b57cec5SDimitry Andric 3200b57cec5SDimitry Andric MCSymbol *GVSym = getSymbol(GV); 3210b57cec5SDimitry Andric 3220b57cec5SDimitry Andric GVSym->redefineIfPossible(); 3230b57cec5SDimitry Andric if (GVSym->isDefined() || GVSym->isVariable()) 3240b57cec5SDimitry Andric report_fatal_error("symbol '" + Twine(GVSym->getName()) + 3250b57cec5SDimitry Andric "' is already defined"); 3260b57cec5SDimitry Andric 327*0fca6ea1SDimitry Andric const DataLayout &DL = GV->getDataLayout(); 3280b57cec5SDimitry Andric uint64_t Size = DL.getTypeAllocSize(GV->getValueType()); 32981ad6265SDimitry Andric Align Alignment = GV->getAlign().value_or(Align(4)); 3300b57cec5SDimitry Andric 3315ffd83dbSDimitry Andric emitVisibility(GVSym, GV->getVisibility(), !GV->isDeclaration()); 3325ffd83dbSDimitry Andric emitLinkage(GV, GVSym); 333bdd1243dSDimitry Andric auto TS = getTargetStreamer(); 3345ffd83dbSDimitry Andric TS->emitAMDGPULDS(GVSym, Size, Alignment); 3350b57cec5SDimitry Andric return; 3360b57cec5SDimitry Andric } 3370b57cec5SDimitry Andric 3385ffd83dbSDimitry Andric AsmPrinter::emitGlobalVariable(GV); 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric 34106c3fb27SDimitry Andric bool AMDGPUAsmPrinter::doInitialization(Module &M) { 3427a6dacacSDimitry Andric CodeObjectVersion = AMDGPU::getAMDHSACodeObjectVersion(M); 34306c3fb27SDimitry Andric 34406c3fb27SDimitry Andric if (TM.getTargetTriple().getOS() == Triple::AMDHSA) { 34506c3fb27SDimitry Andric switch (CodeObjectVersion) { 34606c3fb27SDimitry Andric case AMDGPU::AMDHSA_COV4: 347*0fca6ea1SDimitry Andric HSAMetadataStream = std::make_unique<HSAMD::MetadataStreamerMsgPackV4>(); 34806c3fb27SDimitry Andric break; 34906c3fb27SDimitry Andric case AMDGPU::AMDHSA_COV5: 350*0fca6ea1SDimitry Andric HSAMetadataStream = std::make_unique<HSAMD::MetadataStreamerMsgPackV5>(); 351*0fca6ea1SDimitry Andric break; 352*0fca6ea1SDimitry Andric case AMDGPU::AMDHSA_COV6: 353*0fca6ea1SDimitry Andric HSAMetadataStream = std::make_unique<HSAMD::MetadataStreamerMsgPackV6>(); 35406c3fb27SDimitry Andric break; 35506c3fb27SDimitry Andric default: 35606c3fb27SDimitry Andric report_fatal_error("Unexpected code object version"); 35706c3fb27SDimitry Andric } 35806c3fb27SDimitry Andric } 35906c3fb27SDimitry Andric return AsmPrinter::doInitialization(M); 36006c3fb27SDimitry Andric } 36106c3fb27SDimitry Andric 3620b57cec5SDimitry Andric bool AMDGPUAsmPrinter::doFinalization(Module &M) { 3630b57cec5SDimitry Andric // Pad with s_code_end to help tools and guard against instruction prefetch 3640b57cec5SDimitry Andric // causing stale data in caches. Arguably this should be done by the linker, 3650b57cec5SDimitry Andric // which is why this isn't done for Mesa. 3660b57cec5SDimitry Andric const MCSubtargetInfo &STI = *getGlobalSTI(); 367fe6060f1SDimitry Andric if ((AMDGPU::isGFX10Plus(STI) || AMDGPU::isGFX90A(STI)) && 3680b57cec5SDimitry Andric (STI.getTargetTriple().getOS() == Triple::AMDHSA || 3690b57cec5SDimitry Andric STI.getTargetTriple().getOS() == Triple::AMDPAL)) { 37081ad6265SDimitry Andric OutStreamer->switchSection(getObjFileLowering().getTextSection()); 371fe6060f1SDimitry Andric getTargetStreamer()->EmitCodeEnd(STI); 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric return AsmPrinter::doFinalization(M); 3750b57cec5SDimitry Andric } 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric // Print comments that apply to both callable functions and entry points. 3780b57cec5SDimitry Andric void AMDGPUAsmPrinter::emitCommonFunctionComments( 379bdd1243dSDimitry Andric uint32_t NumVGPR, std::optional<uint32_t> NumAGPR, uint32_t TotalNumVGPR, 380bdd1243dSDimitry Andric uint32_t NumSGPR, uint64_t ScratchSize, uint64_t CodeSize, 3810b57cec5SDimitry Andric const AMDGPUMachineFunction *MFI) { 3820b57cec5SDimitry Andric OutStreamer->emitRawComment(" codeLenInByte = " + Twine(CodeSize), false); 3830b57cec5SDimitry Andric OutStreamer->emitRawComment(" NumSgprs: " + Twine(NumSGPR), false); 3840b57cec5SDimitry Andric OutStreamer->emitRawComment(" NumVgprs: " + Twine(NumVGPR), false); 3858bcb0991SDimitry Andric if (NumAGPR) { 3868bcb0991SDimitry Andric OutStreamer->emitRawComment(" NumAgprs: " + Twine(*NumAGPR), false); 3878bcb0991SDimitry Andric OutStreamer->emitRawComment(" TotalNumVgprs: " + Twine(TotalNumVGPR), 3888bcb0991SDimitry Andric false); 3898bcb0991SDimitry Andric } 3900b57cec5SDimitry Andric OutStreamer->emitRawComment(" ScratchSize: " + Twine(ScratchSize), false); 3910b57cec5SDimitry Andric OutStreamer->emitRawComment(" MemoryBound: " + Twine(MFI->isMemoryBound()), 3920b57cec5SDimitry Andric false); 3930b57cec5SDimitry Andric } 3940b57cec5SDimitry Andric 395*0fca6ea1SDimitry Andric SmallString<128> AMDGPUAsmPrinter::getMCExprStr(const MCExpr *Value) { 396*0fca6ea1SDimitry Andric SmallString<128> Str; 397*0fca6ea1SDimitry Andric raw_svector_ostream OSS(Str); 398*0fca6ea1SDimitry Andric int64_t IVal; 399*0fca6ea1SDimitry Andric if (Value->evaluateAsAbsolute(IVal)) { 400*0fca6ea1SDimitry Andric OSS << static_cast<uint64_t>(IVal); 401*0fca6ea1SDimitry Andric } else { 402*0fca6ea1SDimitry Andric Value->print(OSS, MAI); 403*0fca6ea1SDimitry Andric } 404*0fca6ea1SDimitry Andric return Str; 405*0fca6ea1SDimitry Andric } 406*0fca6ea1SDimitry Andric 407*0fca6ea1SDimitry Andric void AMDGPUAsmPrinter::emitCommonFunctionComments( 408*0fca6ea1SDimitry Andric const MCExpr *NumVGPR, const MCExpr *NumAGPR, const MCExpr *TotalNumVGPR, 409*0fca6ea1SDimitry Andric const MCExpr *NumSGPR, const MCExpr *ScratchSize, uint64_t CodeSize, 410*0fca6ea1SDimitry Andric const AMDGPUMachineFunction *MFI) { 411*0fca6ea1SDimitry Andric OutStreamer->emitRawComment(" codeLenInByte = " + Twine(CodeSize), false); 412*0fca6ea1SDimitry Andric OutStreamer->emitRawComment(" NumSgprs: " + getMCExprStr(NumSGPR), false); 413*0fca6ea1SDimitry Andric OutStreamer->emitRawComment(" NumVgprs: " + getMCExprStr(NumVGPR), false); 414*0fca6ea1SDimitry Andric if (NumAGPR && TotalNumVGPR) { 415*0fca6ea1SDimitry Andric OutStreamer->emitRawComment(" NumAgprs: " + getMCExprStr(NumAGPR), false); 416*0fca6ea1SDimitry Andric OutStreamer->emitRawComment(" TotalNumVgprs: " + getMCExprStr(TotalNumVGPR), 417*0fca6ea1SDimitry Andric false); 418*0fca6ea1SDimitry Andric } 419*0fca6ea1SDimitry Andric OutStreamer->emitRawComment(" ScratchSize: " + getMCExprStr(ScratchSize), 420*0fca6ea1SDimitry Andric false); 421*0fca6ea1SDimitry Andric OutStreamer->emitRawComment(" MemoryBound: " + Twine(MFI->isMemoryBound()), 422*0fca6ea1SDimitry Andric false); 423*0fca6ea1SDimitry Andric } 424*0fca6ea1SDimitry Andric 425*0fca6ea1SDimitry Andric const MCExpr *AMDGPUAsmPrinter::getAmdhsaKernelCodeProperties( 4260b57cec5SDimitry Andric const MachineFunction &MF) const { 4270b57cec5SDimitry Andric const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>(); 428*0fca6ea1SDimitry Andric MCContext &Ctx = MF.getContext(); 4290b57cec5SDimitry Andric uint16_t KernelCodeProperties = 0; 4305f757f3fSDimitry Andric const GCNUserSGPRUsageInfo &UserSGPRInfo = MFI.getUserSGPRInfo(); 4310b57cec5SDimitry Andric 4325f757f3fSDimitry Andric if (UserSGPRInfo.hasPrivateSegmentBuffer()) { 4330b57cec5SDimitry Andric KernelCodeProperties |= 4340b57cec5SDimitry Andric amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER; 4350b57cec5SDimitry Andric } 4365f757f3fSDimitry Andric if (UserSGPRInfo.hasDispatchPtr()) { 4370b57cec5SDimitry Andric KernelCodeProperties |= 4380b57cec5SDimitry Andric amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_PTR; 4390b57cec5SDimitry Andric } 4405f757f3fSDimitry Andric if (UserSGPRInfo.hasQueuePtr() && CodeObjectVersion < AMDGPU::AMDHSA_COV5) { 4410b57cec5SDimitry Andric KernelCodeProperties |= 4420b57cec5SDimitry Andric amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_QUEUE_PTR; 4430b57cec5SDimitry Andric } 4445f757f3fSDimitry Andric if (UserSGPRInfo.hasKernargSegmentPtr()) { 4450b57cec5SDimitry Andric KernelCodeProperties |= 4460b57cec5SDimitry Andric amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_KERNARG_SEGMENT_PTR; 4470b57cec5SDimitry Andric } 4485f757f3fSDimitry Andric if (UserSGPRInfo.hasDispatchID()) { 4490b57cec5SDimitry Andric KernelCodeProperties |= 4500b57cec5SDimitry Andric amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_ID; 4510b57cec5SDimitry Andric } 4525f757f3fSDimitry Andric if (UserSGPRInfo.hasFlatScratchInit()) { 4530b57cec5SDimitry Andric KernelCodeProperties |= 4540b57cec5SDimitry Andric amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_FLAT_SCRATCH_INIT; 4550b57cec5SDimitry Andric } 456*0fca6ea1SDimitry Andric if (UserSGPRInfo.hasPrivateSegmentSize()) { 457*0fca6ea1SDimitry Andric KernelCodeProperties |= 458*0fca6ea1SDimitry Andric amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_SIZE; 459*0fca6ea1SDimitry Andric } 4600b57cec5SDimitry Andric if (MF.getSubtarget<GCNSubtarget>().isWave32()) { 4610b57cec5SDimitry Andric KernelCodeProperties |= 4620b57cec5SDimitry Andric amdhsa::KERNEL_CODE_PROPERTY_ENABLE_WAVEFRONT_SIZE32; 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric 465*0fca6ea1SDimitry Andric // CurrentProgramInfo.DynamicCallStack is a MCExpr and could be 466*0fca6ea1SDimitry Andric // un-evaluatable at this point so it cannot be conditionally checked here. 467*0fca6ea1SDimitry Andric // Instead, we'll directly shift the possibly unknown MCExpr into its place 468*0fca6ea1SDimitry Andric // and bitwise-or it into KernelCodeProperties. 469*0fca6ea1SDimitry Andric const MCExpr *KernelCodePropExpr = 470*0fca6ea1SDimitry Andric MCConstantExpr::create(KernelCodeProperties, Ctx); 471*0fca6ea1SDimitry Andric const MCExpr *OrValue = MCConstantExpr::create( 472*0fca6ea1SDimitry Andric amdhsa::KERNEL_CODE_PROPERTY_USES_DYNAMIC_STACK_SHIFT, Ctx); 473*0fca6ea1SDimitry Andric OrValue = MCBinaryExpr::createShl(CurrentProgramInfo.DynamicCallStack, 474*0fca6ea1SDimitry Andric OrValue, Ctx); 475*0fca6ea1SDimitry Andric KernelCodePropExpr = MCBinaryExpr::createOr(KernelCodePropExpr, OrValue, Ctx); 476fcaf7f86SDimitry Andric 477*0fca6ea1SDimitry Andric return KernelCodePropExpr; 4780b57cec5SDimitry Andric } 4790b57cec5SDimitry Andric 480*0fca6ea1SDimitry Andric MCKernelDescriptor 481*0fca6ea1SDimitry Andric AMDGPUAsmPrinter::getAmdhsaKernelDescriptor(const MachineFunction &MF, 4820b57cec5SDimitry Andric const SIProgramInfo &PI) const { 483fe6060f1SDimitry Andric const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>(); 484fe6060f1SDimitry Andric const Function &F = MF.getFunction(); 4855f757f3fSDimitry Andric const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>(); 486*0fca6ea1SDimitry Andric MCContext &Ctx = MF.getContext(); 487fe6060f1SDimitry Andric 488*0fca6ea1SDimitry Andric MCKernelDescriptor KernelDescriptor; 4890b57cec5SDimitry Andric 490*0fca6ea1SDimitry Andric KernelDescriptor.group_segment_fixed_size = 491*0fca6ea1SDimitry Andric MCConstantExpr::create(PI.LDSSize, Ctx); 4920b57cec5SDimitry Andric KernelDescriptor.private_segment_fixed_size = PI.ScratchSize; 493fe6060f1SDimitry Andric 494fe6060f1SDimitry Andric Align MaxKernArgAlign; 495*0fca6ea1SDimitry Andric KernelDescriptor.kernarg_size = MCConstantExpr::create( 496*0fca6ea1SDimitry Andric STM.getKernArgSegmentSize(F, MaxKernArgAlign), Ctx); 497fe6060f1SDimitry Andric 498*0fca6ea1SDimitry Andric KernelDescriptor.compute_pgm_rsrc1 = PI.getComputePGMRSrc1(STM, Ctx); 499*0fca6ea1SDimitry Andric KernelDescriptor.compute_pgm_rsrc2 = PI.getComputePGMRSrc2(Ctx); 5000b57cec5SDimitry Andric KernelDescriptor.kernel_code_properties = getAmdhsaKernelCodeProperties(MF); 5010b57cec5SDimitry Andric 502*0fca6ea1SDimitry Andric int64_t PGRM_Rsrc3 = 1; 503*0fca6ea1SDimitry Andric bool EvaluatableRsrc3 = 504*0fca6ea1SDimitry Andric CurrentProgramInfo.ComputePGMRSrc3GFX90A->evaluateAsAbsolute(PGRM_Rsrc3); 505*0fca6ea1SDimitry Andric (void)PGRM_Rsrc3; 506*0fca6ea1SDimitry Andric (void)EvaluatableRsrc3; 507*0fca6ea1SDimitry Andric assert(STM.hasGFX90AInsts() || !EvaluatableRsrc3 || 508*0fca6ea1SDimitry Andric static_cast<uint64_t>(PGRM_Rsrc3) == 0); 509*0fca6ea1SDimitry Andric KernelDescriptor.compute_pgm_rsrc3 = CurrentProgramInfo.ComputePGMRSrc3GFX90A; 510fe6060f1SDimitry Andric 511*0fca6ea1SDimitry Andric KernelDescriptor.kernarg_preload = MCConstantExpr::create( 512*0fca6ea1SDimitry Andric AMDGPU::hasKernargPreload(STM) ? Info->getNumKernargPreloadedSGPRs() : 0, 513*0fca6ea1SDimitry Andric Ctx); 5145f757f3fSDimitry Andric 5150b57cec5SDimitry Andric return KernelDescriptor; 5160b57cec5SDimitry Andric } 5170b57cec5SDimitry Andric 5180b57cec5SDimitry Andric bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) { 51981ad6265SDimitry Andric // Init target streamer lazily on the first function so that previous passes 52081ad6265SDimitry Andric // can set metadata. 52181ad6265SDimitry Andric if (!IsTargetStreamerInitialized) 52281ad6265SDimitry Andric initTargetStreamer(*MF.getFunction().getParent()); 52381ad6265SDimitry Andric 524fe6060f1SDimitry Andric ResourceUsage = &getAnalysis<AMDGPUResourceUsageAnalysis>(); 525*0fca6ea1SDimitry Andric CurrentProgramInfo.reset(MF); 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric const AMDGPUMachineFunction *MFI = MF.getInfo<AMDGPUMachineFunction>(); 528*0fca6ea1SDimitry Andric MCContext &Ctx = MF.getContext(); 5290b57cec5SDimitry Andric 5300b57cec5SDimitry Andric // The starting address of all shader programs must be 256 bytes aligned. 5310b57cec5SDimitry Andric // Regular functions just need the basic required instruction alignment. 5328bcb0991SDimitry Andric MF.setAlignment(MFI->isEntryFunction() ? Align(256) : Align(4)); 5330b57cec5SDimitry Andric 5340b57cec5SDimitry Andric SetupMachineFunction(MF); 5350b57cec5SDimitry Andric 5360b57cec5SDimitry Andric const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>(); 5370b57cec5SDimitry Andric MCContext &Context = getObjFileLowering().getContext(); 5380b57cec5SDimitry Andric // FIXME: This should be an explicit check for Mesa. 5390b57cec5SDimitry Andric if (!STM.isAmdHsaOS() && !STM.isAmdPalOS()) { 5400b57cec5SDimitry Andric MCSectionELF *ConfigSection = 5410b57cec5SDimitry Andric Context.getELFSection(".AMDGPU.config", ELF::SHT_PROGBITS, 0); 54281ad6265SDimitry Andric OutStreamer->switchSection(ConfigSection); 5430b57cec5SDimitry Andric } 5440b57cec5SDimitry Andric 545e8d8bef9SDimitry Andric if (MFI->isModuleEntryFunction()) { 5460b57cec5SDimitry Andric getSIProgramInfo(CurrentProgramInfo, MF); 5470b57cec5SDimitry Andric } 5480b57cec5SDimitry Andric 549e8d8bef9SDimitry Andric if (STM.isAmdPalOS()) { 550e8d8bef9SDimitry Andric if (MFI->isEntryFunction()) 5510b57cec5SDimitry Andric EmitPALMetadata(MF, CurrentProgramInfo); 552e8d8bef9SDimitry Andric else if (MFI->isModuleEntryFunction()) 553e8d8bef9SDimitry Andric emitPALFunctionMetadata(MF); 554e8d8bef9SDimitry Andric } else if (!STM.isAmdHsaOS()) { 5550b57cec5SDimitry Andric EmitProgramInfoSI(MF, CurrentProgramInfo); 5560b57cec5SDimitry Andric } 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric DumpCodeInstEmitter = nullptr; 5590b57cec5SDimitry Andric if (STM.dumpCode()) { 560*0fca6ea1SDimitry Andric // For -dumpcode, get the assembler out of the streamer. This only works 561*0fca6ea1SDimitry Andric // with -filetype=obj. 5620b57cec5SDimitry Andric MCAssembler *Assembler = OutStreamer->getAssemblerPtr(); 5630b57cec5SDimitry Andric if (Assembler) 5640b57cec5SDimitry Andric DumpCodeInstEmitter = Assembler->getEmitterPtr(); 5650b57cec5SDimitry Andric } 5660b57cec5SDimitry Andric 5670b57cec5SDimitry Andric DisasmLines.clear(); 5680b57cec5SDimitry Andric HexLines.clear(); 5690b57cec5SDimitry Andric DisasmLineMaxLen = 0; 5700b57cec5SDimitry Andric 5715ffd83dbSDimitry Andric emitFunctionBody(); 5720b57cec5SDimitry Andric 573fcaf7f86SDimitry Andric emitResourceUsageRemarks(MF, CurrentProgramInfo, MFI->isModuleEntryFunction(), 574fcaf7f86SDimitry Andric STM.hasMAIInsts()); 575fcaf7f86SDimitry Andric 5760b57cec5SDimitry Andric if (isVerbose()) { 5770b57cec5SDimitry Andric MCSectionELF *CommentSection = 5780b57cec5SDimitry Andric Context.getELFSection(".AMDGPU.csdata", ELF::SHT_PROGBITS, 0); 57981ad6265SDimitry Andric OutStreamer->switchSection(CommentSection); 5800b57cec5SDimitry Andric 5810b57cec5SDimitry Andric if (!MFI->isEntryFunction()) { 5820b57cec5SDimitry Andric OutStreamer->emitRawComment(" Function info:", false); 583fe6060f1SDimitry Andric const AMDGPUResourceUsageAnalysis::SIFunctionResourceInfo &Info = 584fe6060f1SDimitry Andric ResourceUsage->getResourceInfo(&MF.getFunction()); 5850b57cec5SDimitry Andric emitCommonFunctionComments( 5860b57cec5SDimitry Andric Info.NumVGPR, 587bdd1243dSDimitry Andric STM.hasMAIInsts() ? Info.NumAGPR : std::optional<uint32_t>(), 5888bcb0991SDimitry Andric Info.getTotalNumVGPRs(STM), 5890b57cec5SDimitry Andric Info.getTotalNumSGPRs(MF.getSubtarget<GCNSubtarget>()), 590bdd1243dSDimitry Andric Info.PrivateSegmentSize, getFunctionCodeSize(MF), MFI); 5910b57cec5SDimitry Andric return false; 5920b57cec5SDimitry Andric } 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric OutStreamer->emitRawComment(" Kernel info:", false); 595bdd1243dSDimitry Andric emitCommonFunctionComments( 596bdd1243dSDimitry Andric CurrentProgramInfo.NumArchVGPR, 597*0fca6ea1SDimitry Andric STM.hasMAIInsts() ? CurrentProgramInfo.NumAccVGPR : nullptr, 598bdd1243dSDimitry Andric CurrentProgramInfo.NumVGPR, CurrentProgramInfo.NumSGPR, 599bdd1243dSDimitry Andric CurrentProgramInfo.ScratchSize, getFunctionCodeSize(MF), MFI); 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric OutStreamer->emitRawComment( 6020b57cec5SDimitry Andric " FloatMode: " + Twine(CurrentProgramInfo.FloatMode), false); 6030b57cec5SDimitry Andric OutStreamer->emitRawComment( 6040b57cec5SDimitry Andric " IeeeMode: " + Twine(CurrentProgramInfo.IEEEMode), false); 6050b57cec5SDimitry Andric OutStreamer->emitRawComment( 6060b57cec5SDimitry Andric " LDSByteSize: " + Twine(CurrentProgramInfo.LDSSize) + 6070b57cec5SDimitry Andric " bytes/workgroup (compile time only)", false); 6080b57cec5SDimitry Andric 6090b57cec5SDimitry Andric OutStreamer->emitRawComment( 610*0fca6ea1SDimitry Andric " SGPRBlocks: " + getMCExprStr(CurrentProgramInfo.SGPRBlocks), false); 611*0fca6ea1SDimitry Andric 6120b57cec5SDimitry Andric OutStreamer->emitRawComment( 613*0fca6ea1SDimitry Andric " VGPRBlocks: " + getMCExprStr(CurrentProgramInfo.VGPRBlocks), false); 6140b57cec5SDimitry Andric 6150b57cec5SDimitry Andric OutStreamer->emitRawComment( 6160b57cec5SDimitry Andric " NumSGPRsForWavesPerEU: " + 617*0fca6ea1SDimitry Andric getMCExprStr(CurrentProgramInfo.NumSGPRsForWavesPerEU), 618*0fca6ea1SDimitry Andric false); 6190b57cec5SDimitry Andric OutStreamer->emitRawComment( 6200b57cec5SDimitry Andric " NumVGPRsForWavesPerEU: " + 621*0fca6ea1SDimitry Andric getMCExprStr(CurrentProgramInfo.NumVGPRsForWavesPerEU), 622*0fca6ea1SDimitry Andric false); 6230b57cec5SDimitry Andric 624*0fca6ea1SDimitry Andric if (STM.hasGFX90AInsts()) { 625*0fca6ea1SDimitry Andric const MCExpr *AdjustedAccum = MCBinaryExpr::createAdd( 626*0fca6ea1SDimitry Andric CurrentProgramInfo.AccumOffset, MCConstantExpr::create(1, Ctx), Ctx); 627*0fca6ea1SDimitry Andric AdjustedAccum = MCBinaryExpr::createMul( 628*0fca6ea1SDimitry Andric AdjustedAccum, MCConstantExpr::create(4, Ctx), Ctx); 629fe6060f1SDimitry Andric OutStreamer->emitRawComment( 630*0fca6ea1SDimitry Andric " AccumOffset: " + getMCExprStr(AdjustedAccum), false); 631*0fca6ea1SDimitry Andric } 632fe6060f1SDimitry Andric 6330b57cec5SDimitry Andric OutStreamer->emitRawComment( 634*0fca6ea1SDimitry Andric " Occupancy: " + getMCExprStr(CurrentProgramInfo.Occupancy), false); 6358bcb0991SDimitry Andric 6368bcb0991SDimitry Andric OutStreamer->emitRawComment( 6370b57cec5SDimitry Andric " WaveLimiterHint : " + Twine(MFI->needsWaveLimiter()), false); 6380b57cec5SDimitry Andric 639*0fca6ea1SDimitry Andric OutStreamer->emitRawComment( 640*0fca6ea1SDimitry Andric " COMPUTE_PGM_RSRC2:SCRATCH_EN: " + 641*0fca6ea1SDimitry Andric getMCExprStr(CurrentProgramInfo.ScratchEnable), 64206c3fb27SDimitry Andric false); 64306c3fb27SDimitry Andric OutStreamer->emitRawComment(" COMPUTE_PGM_RSRC2:USER_SGPR: " + 64406c3fb27SDimitry Andric Twine(CurrentProgramInfo.UserSGPR), 64506c3fb27SDimitry Andric false); 64606c3fb27SDimitry Andric OutStreamer->emitRawComment(" COMPUTE_PGM_RSRC2:TRAP_HANDLER: " + 64706c3fb27SDimitry Andric Twine(CurrentProgramInfo.TrapHandlerEnable), 64806c3fb27SDimitry Andric false); 64906c3fb27SDimitry Andric OutStreamer->emitRawComment(" COMPUTE_PGM_RSRC2:TGID_X_EN: " + 65006c3fb27SDimitry Andric Twine(CurrentProgramInfo.TGIdXEnable), 65106c3fb27SDimitry Andric false); 65206c3fb27SDimitry Andric OutStreamer->emitRawComment(" COMPUTE_PGM_RSRC2:TGID_Y_EN: " + 65306c3fb27SDimitry Andric Twine(CurrentProgramInfo.TGIdYEnable), 65406c3fb27SDimitry Andric false); 65506c3fb27SDimitry Andric OutStreamer->emitRawComment(" COMPUTE_PGM_RSRC2:TGID_Z_EN: " + 65606c3fb27SDimitry Andric Twine(CurrentProgramInfo.TGIdZEnable), 65706c3fb27SDimitry Andric false); 65806c3fb27SDimitry Andric OutStreamer->emitRawComment(" COMPUTE_PGM_RSRC2:TIDIG_COMP_CNT: " + 65906c3fb27SDimitry Andric Twine(CurrentProgramInfo.TIdIGCompCount), 6600b57cec5SDimitry Andric false); 661fe6060f1SDimitry Andric 662*0fca6ea1SDimitry Andric [[maybe_unused]] int64_t PGMRSrc3; 663fe6060f1SDimitry Andric assert(STM.hasGFX90AInsts() || 664*0fca6ea1SDimitry Andric (CurrentProgramInfo.ComputePGMRSrc3GFX90A->evaluateAsAbsolute( 665*0fca6ea1SDimitry Andric PGMRSrc3) && 666*0fca6ea1SDimitry Andric static_cast<uint64_t>(PGMRSrc3) == 0)); 667fe6060f1SDimitry Andric if (STM.hasGFX90AInsts()) { 668fe6060f1SDimitry Andric OutStreamer->emitRawComment( 669fe6060f1SDimitry Andric " COMPUTE_PGM_RSRC3_GFX90A:ACCUM_OFFSET: " + 670*0fca6ea1SDimitry Andric getMCExprStr(MCKernelDescriptor::bits_get( 671*0fca6ea1SDimitry Andric CurrentProgramInfo.ComputePGMRSrc3GFX90A, 672*0fca6ea1SDimitry Andric amdhsa::COMPUTE_PGM_RSRC3_GFX90A_ACCUM_OFFSET_SHIFT, 673*0fca6ea1SDimitry Andric amdhsa::COMPUTE_PGM_RSRC3_GFX90A_ACCUM_OFFSET, Ctx)), 674fe6060f1SDimitry Andric false); 675fe6060f1SDimitry Andric OutStreamer->emitRawComment( 676fe6060f1SDimitry Andric " COMPUTE_PGM_RSRC3_GFX90A:TG_SPLIT: " + 677*0fca6ea1SDimitry Andric getMCExprStr(MCKernelDescriptor::bits_get( 678*0fca6ea1SDimitry Andric CurrentProgramInfo.ComputePGMRSrc3GFX90A, 679*0fca6ea1SDimitry Andric amdhsa::COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT_SHIFT, 680*0fca6ea1SDimitry Andric amdhsa::COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT, Ctx)), 681fe6060f1SDimitry Andric false); 682fe6060f1SDimitry Andric } 6830b57cec5SDimitry Andric } 6840b57cec5SDimitry Andric 6850b57cec5SDimitry Andric if (DumpCodeInstEmitter) { 6860b57cec5SDimitry Andric 68781ad6265SDimitry Andric OutStreamer->switchSection( 6885ffd83dbSDimitry Andric Context.getELFSection(".AMDGPU.disasm", ELF::SHT_PROGBITS, 0)); 6890b57cec5SDimitry Andric 6900b57cec5SDimitry Andric for (size_t i = 0; i < DisasmLines.size(); ++i) { 6910b57cec5SDimitry Andric std::string Comment = "\n"; 6920b57cec5SDimitry Andric if (!HexLines[i].empty()) { 6930b57cec5SDimitry Andric Comment = std::string(DisasmLineMaxLen - DisasmLines[i].size(), ' '); 6940b57cec5SDimitry Andric Comment += " ; " + HexLines[i] + "\n"; 6950b57cec5SDimitry Andric } 6960b57cec5SDimitry Andric 6975ffd83dbSDimitry Andric OutStreamer->emitBytes(StringRef(DisasmLines[i])); 6985ffd83dbSDimitry Andric OutStreamer->emitBytes(StringRef(Comment)); 6990b57cec5SDimitry Andric } 7000b57cec5SDimitry Andric } 7010b57cec5SDimitry Andric 7020b57cec5SDimitry Andric return false; 7030b57cec5SDimitry Andric } 7040b57cec5SDimitry Andric 705fe6060f1SDimitry Andric // TODO: Fold this into emitFunctionBodyStart. 706fe6060f1SDimitry Andric void AMDGPUAsmPrinter::initializeTargetID(const Module &M) { 707fe6060f1SDimitry Andric // In the beginning all features are either 'Any' or 'NotSupported', 708fe6060f1SDimitry Andric // depending on global target features. This will cover empty modules. 7097a6dacacSDimitry Andric getTargetStreamer()->initializeTargetID(*getGlobalSTI(), 7107a6dacacSDimitry Andric getGlobalSTI()->getFeatureString()); 711fe6060f1SDimitry Andric 712fe6060f1SDimitry Andric // If module is empty, we are done. 713fe6060f1SDimitry Andric if (M.empty()) 714fe6060f1SDimitry Andric return; 715fe6060f1SDimitry Andric 716fe6060f1SDimitry Andric // If module is not empty, need to find first 'Off' or 'On' feature 717fe6060f1SDimitry Andric // setting per feature from functions in module. 718fe6060f1SDimitry Andric for (auto &F : M) { 719fe6060f1SDimitry Andric auto &TSTargetID = getTargetStreamer()->getTargetID(); 720fe6060f1SDimitry Andric if ((!TSTargetID->isXnackSupported() || TSTargetID->isXnackOnOrOff()) && 721fe6060f1SDimitry Andric (!TSTargetID->isSramEccSupported() || TSTargetID->isSramEccOnOrOff())) 722fe6060f1SDimitry Andric break; 723fe6060f1SDimitry Andric 724fe6060f1SDimitry Andric const GCNSubtarget &STM = TM.getSubtarget<GCNSubtarget>(F); 725fe6060f1SDimitry Andric const IsaInfo::AMDGPUTargetID &STMTargetID = STM.getTargetID(); 726fe6060f1SDimitry Andric if (TSTargetID->isXnackSupported()) 727fe6060f1SDimitry Andric if (TSTargetID->getXnackSetting() == IsaInfo::TargetIDSetting::Any) 728fe6060f1SDimitry Andric TSTargetID->setXnackSetting(STMTargetID.getXnackSetting()); 729fe6060f1SDimitry Andric if (TSTargetID->isSramEccSupported()) 730fe6060f1SDimitry Andric if (TSTargetID->getSramEccSetting() == IsaInfo::TargetIDSetting::Any) 731fe6060f1SDimitry Andric TSTargetID->setSramEccSetting(STMTargetID.getSramEccSetting()); 732fe6060f1SDimitry Andric } 733fe6060f1SDimitry Andric } 734fe6060f1SDimitry Andric 7350b57cec5SDimitry Andric uint64_t AMDGPUAsmPrinter::getFunctionCodeSize(const MachineFunction &MF) const { 7360b57cec5SDimitry Andric const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>(); 7370b57cec5SDimitry Andric const SIInstrInfo *TII = STM.getInstrInfo(); 7380b57cec5SDimitry Andric 7390b57cec5SDimitry Andric uint64_t CodeSize = 0; 7400b57cec5SDimitry Andric 7410b57cec5SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 7420b57cec5SDimitry Andric for (const MachineInstr &MI : MBB) { 7430b57cec5SDimitry Andric // TODO: CodeSize should account for multiple functions. 7440b57cec5SDimitry Andric 7450b57cec5SDimitry Andric // TODO: Should we count size of debug info? 7460b57cec5SDimitry Andric if (MI.isDebugInstr()) 7470b57cec5SDimitry Andric continue; 7480b57cec5SDimitry Andric 7490b57cec5SDimitry Andric CodeSize += TII->getInstSizeInBytes(MI); 7500b57cec5SDimitry Andric } 7510b57cec5SDimitry Andric } 7520b57cec5SDimitry Andric 7530b57cec5SDimitry Andric return CodeSize; 7540b57cec5SDimitry Andric } 7550b57cec5SDimitry Andric 7560b57cec5SDimitry Andric void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo, 7570b57cec5SDimitry Andric const MachineFunction &MF) { 758fe6060f1SDimitry Andric const AMDGPUResourceUsageAnalysis::SIFunctionResourceInfo &Info = 759fe6060f1SDimitry Andric ResourceUsage->getResourceInfo(&MF.getFunction()); 7608bcb0991SDimitry Andric const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>(); 761*0fca6ea1SDimitry Andric MCContext &Ctx = MF.getContext(); 7620b57cec5SDimitry Andric 763*0fca6ea1SDimitry Andric auto CreateExpr = [&Ctx](int64_t Value) { 764*0fca6ea1SDimitry Andric return MCConstantExpr::create(Value, Ctx); 765*0fca6ea1SDimitry Andric }; 766*0fca6ea1SDimitry Andric 767*0fca6ea1SDimitry Andric auto TryGetMCExprValue = [](const MCExpr *Value, uint64_t &Res) -> bool { 768*0fca6ea1SDimitry Andric int64_t Val; 769*0fca6ea1SDimitry Andric if (Value->evaluateAsAbsolute(Val)) { 770*0fca6ea1SDimitry Andric Res = Val; 771*0fca6ea1SDimitry Andric return true; 772*0fca6ea1SDimitry Andric } 773*0fca6ea1SDimitry Andric return false; 774*0fca6ea1SDimitry Andric }; 775*0fca6ea1SDimitry Andric 776*0fca6ea1SDimitry Andric ProgInfo.NumArchVGPR = CreateExpr(Info.NumVGPR); 777*0fca6ea1SDimitry Andric ProgInfo.NumAccVGPR = CreateExpr(Info.NumAGPR); 778*0fca6ea1SDimitry Andric ProgInfo.NumVGPR = CreateExpr(Info.getTotalNumVGPRs(STM)); 779*0fca6ea1SDimitry Andric ProgInfo.AccumOffset = 780*0fca6ea1SDimitry Andric CreateExpr(alignTo(std::max(1, Info.NumVGPR), 4) / 4 - 1); 781fe6060f1SDimitry Andric ProgInfo.TgSplit = STM.isTgSplitEnabled(); 782*0fca6ea1SDimitry Andric ProgInfo.NumSGPR = CreateExpr(Info.NumExplicitSGPR); 783*0fca6ea1SDimitry Andric ProgInfo.ScratchSize = CreateExpr(Info.PrivateSegmentSize); 784*0fca6ea1SDimitry Andric ProgInfo.VCCUsed = CreateExpr(Info.UsesVCC); 785*0fca6ea1SDimitry Andric ProgInfo.FlatUsed = CreateExpr(Info.UsesFlatScratch); 786*0fca6ea1SDimitry Andric ProgInfo.DynamicCallStack = 787*0fca6ea1SDimitry Andric CreateExpr(Info.HasDynamicallySizedStack || Info.HasRecursion); 7880b57cec5SDimitry Andric 789e8d8bef9SDimitry Andric const uint64_t MaxScratchPerWorkitem = 79081ad6265SDimitry Andric STM.getMaxWaveScratchSize() / STM.getWavefrontSize(); 791*0fca6ea1SDimitry Andric uint64_t ScratchSize; 792*0fca6ea1SDimitry Andric if (TryGetMCExprValue(ProgInfo.ScratchSize, ScratchSize) && 793*0fca6ea1SDimitry Andric ScratchSize > MaxScratchPerWorkitem) { 794*0fca6ea1SDimitry Andric DiagnosticInfoStackSize DiagStackSize(MF.getFunction(), ScratchSize, 795349cc55cSDimitry Andric MaxScratchPerWorkitem, DS_Error); 7960b57cec5SDimitry Andric MF.getFunction().getContext().diagnose(DiagStackSize); 7970b57cec5SDimitry Andric } 7980b57cec5SDimitry Andric 7990b57cec5SDimitry Andric const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 8000b57cec5SDimitry Andric 801fe6060f1SDimitry Andric // The calculations related to SGPR/VGPR blocks are 8020b57cec5SDimitry Andric // duplicated in part in AMDGPUAsmParser::calculateGPRBlocks, and could be 8030b57cec5SDimitry Andric // unified. 804*0fca6ea1SDimitry Andric const MCExpr *ExtraSGPRs = AMDGPUMCExpr::createExtraSGPRs( 805*0fca6ea1SDimitry Andric ProgInfo.VCCUsed, ProgInfo.FlatUsed, 806*0fca6ea1SDimitry Andric getTargetStreamer()->getTargetID()->isXnackOnOrAny(), Ctx); 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric // Check the addressable register limit before we add ExtraSGPRs. 8090b57cec5SDimitry Andric if (STM.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS && 8100b57cec5SDimitry Andric !STM.hasSGPRInitBug()) { 8110b57cec5SDimitry Andric unsigned MaxAddressableNumSGPRs = STM.getAddressableNumSGPRs(); 812*0fca6ea1SDimitry Andric uint64_t NumSgpr; 813*0fca6ea1SDimitry Andric if (TryGetMCExprValue(ProgInfo.NumSGPR, NumSgpr) && 814*0fca6ea1SDimitry Andric NumSgpr > MaxAddressableNumSGPRs) { 8150b57cec5SDimitry Andric // This can happen due to a compiler bug or when using inline asm. 8160b57cec5SDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 817349cc55cSDimitry Andric DiagnosticInfoResourceLimit Diag( 818*0fca6ea1SDimitry Andric MF.getFunction(), "addressable scalar registers", NumSgpr, 819349cc55cSDimitry Andric MaxAddressableNumSGPRs, DS_Error, DK_ResourceLimit); 8200b57cec5SDimitry Andric Ctx.diagnose(Diag); 821*0fca6ea1SDimitry Andric ProgInfo.NumSGPR = CreateExpr(MaxAddressableNumSGPRs - 1); 8220b57cec5SDimitry Andric } 8230b57cec5SDimitry Andric } 8240b57cec5SDimitry Andric 8250b57cec5SDimitry Andric // Account for extra SGPRs and VGPRs reserved for debugger use. 826*0fca6ea1SDimitry Andric ProgInfo.NumSGPR = MCBinaryExpr::createAdd(ProgInfo.NumSGPR, ExtraSGPRs, Ctx); 8270b57cec5SDimitry Andric 828e8d8bef9SDimitry Andric const Function &F = MF.getFunction(); 829e8d8bef9SDimitry Andric 8300b57cec5SDimitry Andric // Ensure there are enough SGPRs and VGPRs for wave dispatch, where wave 8310b57cec5SDimitry Andric // dispatch registers are function args. 8320b57cec5SDimitry Andric unsigned WaveDispatchNumSGPR = 0, WaveDispatchNumVGPR = 0; 833e8d8bef9SDimitry Andric 834e8d8bef9SDimitry Andric if (isShader(F.getCallingConv())) { 835349cc55cSDimitry Andric bool IsPixelShader = 836349cc55cSDimitry Andric F.getCallingConv() == CallingConv::AMDGPU_PS && !STM.isAmdHsaOS(); 837349cc55cSDimitry Andric 838349cc55cSDimitry Andric // Calculate the number of VGPR registers based on the SPI input registers 839349cc55cSDimitry Andric uint32_t InputEna = 0; 840349cc55cSDimitry Andric uint32_t InputAddr = 0; 841349cc55cSDimitry Andric unsigned LastEna = 0; 842349cc55cSDimitry Andric 843349cc55cSDimitry Andric if (IsPixelShader) { 844349cc55cSDimitry Andric // Note for IsPixelShader: 845349cc55cSDimitry Andric // By this stage, all enabled inputs are tagged in InputAddr as well. 846349cc55cSDimitry Andric // We will use InputAddr to determine whether the input counts against the 847349cc55cSDimitry Andric // vgpr total and only use the InputEnable to determine the last input 848349cc55cSDimitry Andric // that is relevant - if extra arguments are used, then we have to honour 849349cc55cSDimitry Andric // the InputAddr for any intermediate non-enabled inputs. 850349cc55cSDimitry Andric InputEna = MFI->getPSInputEnable(); 851349cc55cSDimitry Andric InputAddr = MFI->getPSInputAddr(); 852349cc55cSDimitry Andric 853349cc55cSDimitry Andric // We only need to consider input args up to the last used arg. 854349cc55cSDimitry Andric assert((InputEna || InputAddr) && 855349cc55cSDimitry Andric "PSInputAddr and PSInputEnable should " 856349cc55cSDimitry Andric "never both be 0 for AMDGPU_PS shaders"); 857349cc55cSDimitry Andric // There are some rare circumstances where InputAddr is non-zero and 858349cc55cSDimitry Andric // InputEna can be set to 0. In this case we default to setting LastEna 859349cc55cSDimitry Andric // to 1. 86006c3fb27SDimitry Andric LastEna = InputEna ? llvm::Log2_32(InputEna) + 1 : 1; 861349cc55cSDimitry Andric } 862349cc55cSDimitry Andric 863e8d8bef9SDimitry Andric // FIXME: We should be using the number of registers determined during 864e8d8bef9SDimitry Andric // calling convention lowering to legalize the types. 865*0fca6ea1SDimitry Andric const DataLayout &DL = F.getDataLayout(); 866349cc55cSDimitry Andric unsigned PSArgCount = 0; 867349cc55cSDimitry Andric unsigned IntermediateVGPR = 0; 868e8d8bef9SDimitry Andric for (auto &Arg : F.args()) { 869e8d8bef9SDimitry Andric unsigned NumRegs = (DL.getTypeSizeInBits(Arg.getType()) + 31) / 32; 870349cc55cSDimitry Andric if (Arg.hasAttribute(Attribute::InReg)) { 8710b57cec5SDimitry Andric WaveDispatchNumSGPR += NumRegs; 872349cc55cSDimitry Andric } else { 873349cc55cSDimitry Andric // If this is a PS shader and we're processing the PS Input args (first 874349cc55cSDimitry Andric // 16 VGPR), use the InputEna and InputAddr bits to define how many 875349cc55cSDimitry Andric // VGPRs are actually used. 876349cc55cSDimitry Andric // Any extra VGPR arguments are handled as normal arguments (and 877349cc55cSDimitry Andric // contribute to the VGPR count whether they're used or not). 878349cc55cSDimitry Andric if (IsPixelShader && PSArgCount < 16) { 879349cc55cSDimitry Andric if ((1 << PSArgCount) & InputAddr) { 880349cc55cSDimitry Andric if (PSArgCount < LastEna) 881349cc55cSDimitry Andric WaveDispatchNumVGPR += NumRegs; 8820b57cec5SDimitry Andric else 883349cc55cSDimitry Andric IntermediateVGPR += NumRegs; 884349cc55cSDimitry Andric } 885349cc55cSDimitry Andric PSArgCount++; 886349cc55cSDimitry Andric } else { 887349cc55cSDimitry Andric // If there are extra arguments we have to include the allocation for 888349cc55cSDimitry Andric // the non-used (but enabled with InputAddr) input arguments 889349cc55cSDimitry Andric if (IntermediateVGPR) { 890349cc55cSDimitry Andric WaveDispatchNumVGPR += IntermediateVGPR; 891349cc55cSDimitry Andric IntermediateVGPR = 0; 892349cc55cSDimitry Andric } 8930b57cec5SDimitry Andric WaveDispatchNumVGPR += NumRegs; 8940b57cec5SDimitry Andric } 895349cc55cSDimitry Andric } 896349cc55cSDimitry Andric } 897*0fca6ea1SDimitry Andric ProgInfo.NumSGPR = AMDGPUMCExpr::createMax( 898*0fca6ea1SDimitry Andric {ProgInfo.NumSGPR, CreateExpr(WaveDispatchNumSGPR)}, Ctx); 899*0fca6ea1SDimitry Andric 900*0fca6ea1SDimitry Andric ProgInfo.NumArchVGPR = AMDGPUMCExpr::createMax( 901*0fca6ea1SDimitry Andric {ProgInfo.NumVGPR, CreateExpr(WaveDispatchNumVGPR)}, Ctx); 902*0fca6ea1SDimitry Andric 903*0fca6ea1SDimitry Andric ProgInfo.NumVGPR = AMDGPUMCExpr::createTotalNumVGPR( 904*0fca6ea1SDimitry Andric ProgInfo.NumAccVGPR, ProgInfo.NumArchVGPR, Ctx); 905e8d8bef9SDimitry Andric } 9060b57cec5SDimitry Andric 9070b57cec5SDimitry Andric // Adjust number of registers used to meet default/requested minimum/maximum 9080b57cec5SDimitry Andric // number of waves per execution unit request. 909*0fca6ea1SDimitry Andric unsigned MaxWaves = MFI->getMaxWavesPerEU(); 910*0fca6ea1SDimitry Andric ProgInfo.NumSGPRsForWavesPerEU = 911*0fca6ea1SDimitry Andric AMDGPUMCExpr::createMax({ProgInfo.NumSGPR, CreateExpr(1ul), 912*0fca6ea1SDimitry Andric CreateExpr(STM.getMinNumSGPRs(MaxWaves))}, 913*0fca6ea1SDimitry Andric Ctx); 914*0fca6ea1SDimitry Andric ProgInfo.NumVGPRsForWavesPerEU = 915*0fca6ea1SDimitry Andric AMDGPUMCExpr::createMax({ProgInfo.NumVGPR, CreateExpr(1ul), 916*0fca6ea1SDimitry Andric CreateExpr(STM.getMinNumVGPRs(MaxWaves))}, 917*0fca6ea1SDimitry Andric Ctx); 9180b57cec5SDimitry Andric 9190b57cec5SDimitry Andric if (STM.getGeneration() <= AMDGPUSubtarget::SEA_ISLANDS || 9200b57cec5SDimitry Andric STM.hasSGPRInitBug()) { 9210b57cec5SDimitry Andric unsigned MaxAddressableNumSGPRs = STM.getAddressableNumSGPRs(); 922*0fca6ea1SDimitry Andric uint64_t NumSgpr; 923*0fca6ea1SDimitry Andric if (TryGetMCExprValue(ProgInfo.NumSGPR, NumSgpr) && 924*0fca6ea1SDimitry Andric NumSgpr > MaxAddressableNumSGPRs) { 9250b57cec5SDimitry Andric // This can happen due to a compiler bug or when using inline asm to use 9260b57cec5SDimitry Andric // the registers which are usually reserved for vcc etc. 9270b57cec5SDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 928349cc55cSDimitry Andric DiagnosticInfoResourceLimit Diag(MF.getFunction(), "scalar registers", 929*0fca6ea1SDimitry Andric NumSgpr, MaxAddressableNumSGPRs, 930349cc55cSDimitry Andric DS_Error, DK_ResourceLimit); 9310b57cec5SDimitry Andric Ctx.diagnose(Diag); 932*0fca6ea1SDimitry Andric ProgInfo.NumSGPR = CreateExpr(MaxAddressableNumSGPRs); 933*0fca6ea1SDimitry Andric ProgInfo.NumSGPRsForWavesPerEU = CreateExpr(MaxAddressableNumSGPRs); 9340b57cec5SDimitry Andric } 9350b57cec5SDimitry Andric } 9360b57cec5SDimitry Andric 9370b57cec5SDimitry Andric if (STM.hasSGPRInitBug()) { 9380b57cec5SDimitry Andric ProgInfo.NumSGPR = 939*0fca6ea1SDimitry Andric CreateExpr(AMDGPU::IsaInfo::FIXED_NUM_SGPRS_FOR_INIT_BUG); 9400b57cec5SDimitry Andric ProgInfo.NumSGPRsForWavesPerEU = 941*0fca6ea1SDimitry Andric CreateExpr(AMDGPU::IsaInfo::FIXED_NUM_SGPRS_FOR_INIT_BUG); 9420b57cec5SDimitry Andric } 9430b57cec5SDimitry Andric 9440b57cec5SDimitry Andric if (MFI->getNumUserSGPRs() > STM.getMaxNumUserSGPRs()) { 9450b57cec5SDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 9460b57cec5SDimitry Andric DiagnosticInfoResourceLimit Diag(MF.getFunction(), "user SGPRs", 947349cc55cSDimitry Andric MFI->getNumUserSGPRs(), 948349cc55cSDimitry Andric STM.getMaxNumUserSGPRs(), DS_Error); 9490b57cec5SDimitry Andric Ctx.diagnose(Diag); 9500b57cec5SDimitry Andric } 9510b57cec5SDimitry Andric 952bdd1243dSDimitry Andric if (MFI->getLDSSize() > 953bdd1243dSDimitry Andric static_cast<unsigned>(STM.getAddressableLocalMemorySize())) { 9540b57cec5SDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 955bdd1243dSDimitry Andric DiagnosticInfoResourceLimit Diag( 956bdd1243dSDimitry Andric MF.getFunction(), "local memory", MFI->getLDSSize(), 957bdd1243dSDimitry Andric STM.getAddressableLocalMemorySize(), DS_Error); 9580b57cec5SDimitry Andric Ctx.diagnose(Diag); 9590b57cec5SDimitry Andric } 960*0fca6ea1SDimitry Andric // The MCExpr equivalent of getNumSGPRBlocks/getNumVGPRBlocks: 961*0fca6ea1SDimitry Andric // (alignTo(max(1u, NumGPR), GPREncodingGranule) / GPREncodingGranule) - 1 962*0fca6ea1SDimitry Andric auto GetNumGPRBlocks = [&CreateExpr, &Ctx](const MCExpr *NumGPR, 963*0fca6ea1SDimitry Andric unsigned Granule) { 964*0fca6ea1SDimitry Andric const MCExpr *OneConst = CreateExpr(1ul); 965*0fca6ea1SDimitry Andric const MCExpr *GranuleConst = CreateExpr(Granule); 966*0fca6ea1SDimitry Andric const MCExpr *MaxNumGPR = AMDGPUMCExpr::createMax({NumGPR, OneConst}, Ctx); 967*0fca6ea1SDimitry Andric const MCExpr *AlignToGPR = 968*0fca6ea1SDimitry Andric AMDGPUMCExpr::createAlignTo(MaxNumGPR, GranuleConst, Ctx); 969*0fca6ea1SDimitry Andric const MCExpr *DivGPR = 970*0fca6ea1SDimitry Andric MCBinaryExpr::createDiv(AlignToGPR, GranuleConst, Ctx); 971*0fca6ea1SDimitry Andric const MCExpr *SubGPR = MCBinaryExpr::createSub(DivGPR, OneConst, Ctx); 972*0fca6ea1SDimitry Andric return SubGPR; 973*0fca6ea1SDimitry Andric }; 9740b57cec5SDimitry Andric 975*0fca6ea1SDimitry Andric ProgInfo.SGPRBlocks = GetNumGPRBlocks(ProgInfo.NumSGPRsForWavesPerEU, 976*0fca6ea1SDimitry Andric IsaInfo::getSGPREncodingGranule(&STM)); 977*0fca6ea1SDimitry Andric ProgInfo.VGPRBlocks = GetNumGPRBlocks(ProgInfo.NumVGPRsForWavesPerEU, 978*0fca6ea1SDimitry Andric IsaInfo::getVGPREncodingGranule(&STM)); 9790b57cec5SDimitry Andric 980480093f4SDimitry Andric const SIModeRegisterDefaults Mode = MFI->getMode(); 981480093f4SDimitry Andric 9820b57cec5SDimitry Andric // Set the value to initialize FP_ROUND and FP_DENORM parts of the mode 9830b57cec5SDimitry Andric // register. 984480093f4SDimitry Andric ProgInfo.FloatMode = getFPMode(Mode); 9850b57cec5SDimitry Andric 9860b57cec5SDimitry Andric ProgInfo.IEEEMode = Mode.IEEE; 9870b57cec5SDimitry Andric 9880b57cec5SDimitry Andric // Make clamp modifier on NaN input returns 0. 9890b57cec5SDimitry Andric ProgInfo.DX10Clamp = Mode.DX10Clamp; 9900b57cec5SDimitry Andric 9910b57cec5SDimitry Andric unsigned LDSAlignShift; 9920b57cec5SDimitry Andric if (STM.getGeneration() < AMDGPUSubtarget::SEA_ISLANDS) { 9930b57cec5SDimitry Andric // LDS is allocated in 64 dword blocks. 9940b57cec5SDimitry Andric LDSAlignShift = 8; 9950b57cec5SDimitry Andric } else { 9960b57cec5SDimitry Andric // LDS is allocated in 128 dword blocks. 9970b57cec5SDimitry Andric LDSAlignShift = 9; 9980b57cec5SDimitry Andric } 9990b57cec5SDimitry Andric 1000fcaf7f86SDimitry Andric ProgInfo.SGPRSpill = MFI->getNumSpilledSGPRs(); 1001fcaf7f86SDimitry Andric ProgInfo.VGPRSpill = MFI->getNumSpilledVGPRs(); 1002fcaf7f86SDimitry Andric 100381ad6265SDimitry Andric ProgInfo.LDSSize = MFI->getLDSSize(); 10040b57cec5SDimitry Andric ProgInfo.LDSBlocks = 10050b57cec5SDimitry Andric alignTo(ProgInfo.LDSSize, 1ULL << LDSAlignShift) >> LDSAlignShift; 10060b57cec5SDimitry Andric 1007*0fca6ea1SDimitry Andric // The MCExpr equivalent of divideCeil. 1008*0fca6ea1SDimitry Andric auto DivideCeil = [&Ctx](const MCExpr *Numerator, const MCExpr *Denominator) { 1009*0fca6ea1SDimitry Andric const MCExpr *Ceil = 1010*0fca6ea1SDimitry Andric AMDGPUMCExpr::createAlignTo(Numerator, Denominator, Ctx); 1011*0fca6ea1SDimitry Andric return MCBinaryExpr::createDiv(Ceil, Denominator, Ctx); 1012*0fca6ea1SDimitry Andric }; 1013*0fca6ea1SDimitry Andric 101481ad6265SDimitry Andric // Scratch is allocated in 64-dword or 256-dword blocks. 101581ad6265SDimitry Andric unsigned ScratchAlignShift = 101681ad6265SDimitry Andric STM.getGeneration() >= AMDGPUSubtarget::GFX11 ? 8 : 10; 10170b57cec5SDimitry Andric // We need to program the hardware with the amount of scratch memory that 10180b57cec5SDimitry Andric // is used by the entire wave. ProgInfo.ScratchSize is the amount of 10190b57cec5SDimitry Andric // scratch memory used per thread. 1020*0fca6ea1SDimitry Andric ProgInfo.ScratchBlocks = DivideCeil( 1021*0fca6ea1SDimitry Andric MCBinaryExpr::createMul(ProgInfo.ScratchSize, 1022*0fca6ea1SDimitry Andric CreateExpr(STM.getWavefrontSize()), Ctx), 1023*0fca6ea1SDimitry Andric CreateExpr(1ULL << ScratchAlignShift)); 10240b57cec5SDimitry Andric 10250b57cec5SDimitry Andric if (getIsaVersion(getGlobalSTI()->getCPU()).Major >= 10) { 10260b57cec5SDimitry Andric ProgInfo.WgpMode = STM.isCuModeEnabled() ? 0 : 1; 10270b57cec5SDimitry Andric ProgInfo.MemOrdered = 1; 10280b57cec5SDimitry Andric } 10290b57cec5SDimitry Andric 10300b57cec5SDimitry Andric // 0 = X, 1 = XY, 2 = XYZ 10310b57cec5SDimitry Andric unsigned TIDIGCompCnt = 0; 10320b57cec5SDimitry Andric if (MFI->hasWorkItemIDZ()) 10330b57cec5SDimitry Andric TIDIGCompCnt = 2; 10340b57cec5SDimitry Andric else if (MFI->hasWorkItemIDY()) 10350b57cec5SDimitry Andric TIDIGCompCnt = 1; 10360b57cec5SDimitry Andric 103781ad6265SDimitry Andric // The private segment wave byte offset is the last of the system SGPRs. We 103881ad6265SDimitry Andric // initially assumed it was allocated, and may have used it. It shouldn't harm 103981ad6265SDimitry Andric // anything to disable it if we know the stack isn't used here. We may still 104081ad6265SDimitry Andric // have emitted code reading it to initialize scratch, but if that's unused 104181ad6265SDimitry Andric // reading garbage should be OK. 1042*0fca6ea1SDimitry Andric ProgInfo.ScratchEnable = MCBinaryExpr::createLOr( 1043*0fca6ea1SDimitry Andric MCBinaryExpr::createGT(ProgInfo.ScratchBlocks, 1044*0fca6ea1SDimitry Andric MCConstantExpr::create(0, Ctx), Ctx), 1045*0fca6ea1SDimitry Andric ProgInfo.DynamicCallStack, Ctx); 1046*0fca6ea1SDimitry Andric 104706c3fb27SDimitry Andric ProgInfo.UserSGPR = MFI->getNumUserSGPRs(); 10480b57cec5SDimitry Andric // For AMDHSA, TRAP_HANDLER must be zero, as it is populated by the CP. 104906c3fb27SDimitry Andric ProgInfo.TrapHandlerEnable = 105006c3fb27SDimitry Andric STM.isAmdHsaOS() ? 0 : STM.isTrapHandlerEnabled(); 105106c3fb27SDimitry Andric ProgInfo.TGIdXEnable = MFI->hasWorkGroupIDX(); 105206c3fb27SDimitry Andric ProgInfo.TGIdYEnable = MFI->hasWorkGroupIDY(); 105306c3fb27SDimitry Andric ProgInfo.TGIdZEnable = MFI->hasWorkGroupIDZ(); 105406c3fb27SDimitry Andric ProgInfo.TGSizeEnable = MFI->hasWorkGroupInfo(); 105506c3fb27SDimitry Andric ProgInfo.TIdIGCompCount = TIDIGCompCnt; 105606c3fb27SDimitry Andric ProgInfo.EXCPEnMSB = 0; 10570b57cec5SDimitry Andric // For AMDHSA, LDS_SIZE must be zero, as it is populated by the CP. 105806c3fb27SDimitry Andric ProgInfo.LdsSize = STM.isAmdHsaOS() ? 0 : ProgInfo.LDSBlocks; 105906c3fb27SDimitry Andric ProgInfo.EXCPEnable = 0; 10608bcb0991SDimitry Andric 1061fe6060f1SDimitry Andric if (STM.hasGFX90AInsts()) { 1062*0fca6ea1SDimitry Andric // return ((Dst & ~Mask) | (Value << Shift)) 1063*0fca6ea1SDimitry Andric auto SetBits = [&Ctx](const MCExpr *Dst, const MCExpr *Value, uint32_t Mask, 1064*0fca6ea1SDimitry Andric uint32_t Shift) { 1065*0fca6ea1SDimitry Andric auto Shft = MCConstantExpr::create(Shift, Ctx); 1066*0fca6ea1SDimitry Andric auto Msk = MCConstantExpr::create(Mask, Ctx); 1067*0fca6ea1SDimitry Andric Dst = MCBinaryExpr::createAnd(Dst, MCUnaryExpr::createNot(Msk, Ctx), Ctx); 1068*0fca6ea1SDimitry Andric Dst = MCBinaryExpr::createOr( 1069*0fca6ea1SDimitry Andric Dst, MCBinaryExpr::createShl(Value, Shft, Ctx), Ctx); 1070*0fca6ea1SDimitry Andric return Dst; 1071*0fca6ea1SDimitry Andric }; 1072*0fca6ea1SDimitry Andric 1073*0fca6ea1SDimitry Andric ProgInfo.ComputePGMRSrc3GFX90A = 1074*0fca6ea1SDimitry Andric SetBits(ProgInfo.ComputePGMRSrc3GFX90A, ProgInfo.AccumOffset, 1075fe6060f1SDimitry Andric amdhsa::COMPUTE_PGM_RSRC3_GFX90A_ACCUM_OFFSET, 1076*0fca6ea1SDimitry Andric amdhsa::COMPUTE_PGM_RSRC3_GFX90A_ACCUM_OFFSET_SHIFT); 1077*0fca6ea1SDimitry Andric ProgInfo.ComputePGMRSrc3GFX90A = 1078*0fca6ea1SDimitry Andric SetBits(ProgInfo.ComputePGMRSrc3GFX90A, CreateExpr(ProgInfo.TgSplit), 1079fe6060f1SDimitry Andric amdhsa::COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT, 1080*0fca6ea1SDimitry Andric amdhsa::COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT_SHIFT); 1081fe6060f1SDimitry Andric } 1082fe6060f1SDimitry Andric 1083*0fca6ea1SDimitry Andric ProgInfo.Occupancy = AMDGPUMCExpr::createOccupancy( 1084*0fca6ea1SDimitry Andric STM.computeOccupancy(F, ProgInfo.LDSSize), ProgInfo.NumSGPRsForWavesPerEU, 1085*0fca6ea1SDimitry Andric ProgInfo.NumVGPRsForWavesPerEU, STM, Ctx); 1086*0fca6ea1SDimitry Andric 10875f757f3fSDimitry Andric const auto [MinWEU, MaxWEU] = 10885f757f3fSDimitry Andric AMDGPU::getIntegerPairAttribute(F, "amdgpu-waves-per-eu", {0, 0}, true); 1089*0fca6ea1SDimitry Andric uint64_t Occupancy; 1090*0fca6ea1SDimitry Andric if (TryGetMCExprValue(ProgInfo.Occupancy, Occupancy) && Occupancy < MinWEU) { 10915f757f3fSDimitry Andric DiagnosticInfoOptimizationFailure Diag( 10925f757f3fSDimitry Andric F, F.getSubprogram(), 10935f757f3fSDimitry Andric "failed to meet occupancy target given by 'amdgpu-waves-per-eu' in " 10945f757f3fSDimitry Andric "'" + 10955f757f3fSDimitry Andric F.getName() + "': desired occupancy was " + Twine(MinWEU) + 1096*0fca6ea1SDimitry Andric ", final occupancy is " + Twine(Occupancy)); 10975f757f3fSDimitry Andric F.getContext().diagnose(Diag); 10985f757f3fSDimitry Andric } 10990b57cec5SDimitry Andric } 11000b57cec5SDimitry Andric 11010b57cec5SDimitry Andric static unsigned getRsrcReg(CallingConv::ID CallConv) { 11020b57cec5SDimitry Andric switch (CallConv) { 1103bdd1243dSDimitry Andric default: [[fallthrough]]; 11040b57cec5SDimitry Andric case CallingConv::AMDGPU_CS: return R_00B848_COMPUTE_PGM_RSRC1; 11050b57cec5SDimitry Andric case CallingConv::AMDGPU_LS: return R_00B528_SPI_SHADER_PGM_RSRC1_LS; 11060b57cec5SDimitry Andric case CallingConv::AMDGPU_HS: return R_00B428_SPI_SHADER_PGM_RSRC1_HS; 11070b57cec5SDimitry Andric case CallingConv::AMDGPU_ES: return R_00B328_SPI_SHADER_PGM_RSRC1_ES; 11080b57cec5SDimitry Andric case CallingConv::AMDGPU_GS: return R_00B228_SPI_SHADER_PGM_RSRC1_GS; 11090b57cec5SDimitry Andric case CallingConv::AMDGPU_VS: return R_00B128_SPI_SHADER_PGM_RSRC1_VS; 11100b57cec5SDimitry Andric case CallingConv::AMDGPU_PS: return R_00B028_SPI_SHADER_PGM_RSRC1_PS; 11110b57cec5SDimitry Andric } 11120b57cec5SDimitry Andric } 11130b57cec5SDimitry Andric 11140b57cec5SDimitry Andric void AMDGPUAsmPrinter::EmitProgramInfoSI(const MachineFunction &MF, 11150b57cec5SDimitry Andric const SIProgramInfo &CurrentProgramInfo) { 11160b57cec5SDimitry Andric const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 111781ad6265SDimitry Andric const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>(); 11180b57cec5SDimitry Andric unsigned RsrcReg = getRsrcReg(MF.getFunction().getCallingConv()); 1119*0fca6ea1SDimitry Andric MCContext &Ctx = MF.getContext(); 1120*0fca6ea1SDimitry Andric 1121*0fca6ea1SDimitry Andric // (((Value) & Mask) << Shift) 1122*0fca6ea1SDimitry Andric auto SetBits = [&Ctx](const MCExpr *Value, uint32_t Mask, uint32_t Shift) { 1123*0fca6ea1SDimitry Andric const MCExpr *msk = MCConstantExpr::create(Mask, Ctx); 1124*0fca6ea1SDimitry Andric const MCExpr *shft = MCConstantExpr::create(Shift, Ctx); 1125*0fca6ea1SDimitry Andric return MCBinaryExpr::createShl(MCBinaryExpr::createAnd(Value, msk, Ctx), 1126*0fca6ea1SDimitry Andric shft, Ctx); 1127*0fca6ea1SDimitry Andric }; 1128*0fca6ea1SDimitry Andric 1129*0fca6ea1SDimitry Andric auto EmitResolvedOrExpr = [this](const MCExpr *Value, unsigned Size) { 1130*0fca6ea1SDimitry Andric int64_t Val; 1131*0fca6ea1SDimitry Andric if (Value->evaluateAsAbsolute(Val)) 1132*0fca6ea1SDimitry Andric OutStreamer->emitIntValue(static_cast<uint64_t>(Val), Size); 1133*0fca6ea1SDimitry Andric else 1134*0fca6ea1SDimitry Andric OutStreamer->emitValue(Value, Size); 1135*0fca6ea1SDimitry Andric }; 11360b57cec5SDimitry Andric 11370b57cec5SDimitry Andric if (AMDGPU::isCompute(MF.getFunction().getCallingConv())) { 11385ffd83dbSDimitry Andric OutStreamer->emitInt32(R_00B848_COMPUTE_PGM_RSRC1); 11390b57cec5SDimitry Andric 1140*0fca6ea1SDimitry Andric EmitResolvedOrExpr(CurrentProgramInfo.getComputePGMRSrc1(STM, Ctx), 1141*0fca6ea1SDimitry Andric /*Size=*/4); 11420b57cec5SDimitry Andric 11435ffd83dbSDimitry Andric OutStreamer->emitInt32(R_00B84C_COMPUTE_PGM_RSRC2); 1144*0fca6ea1SDimitry Andric EmitResolvedOrExpr(CurrentProgramInfo.getComputePGMRSrc2(Ctx), /*Size=*/4); 11450b57cec5SDimitry Andric 11465ffd83dbSDimitry Andric OutStreamer->emitInt32(R_00B860_COMPUTE_TMPRING_SIZE); 1147*0fca6ea1SDimitry Andric 1148*0fca6ea1SDimitry Andric // Sets bits according to S_0286E8_WAVESIZE_* mask and shift values for the 1149*0fca6ea1SDimitry Andric // appropriate generation. 1150*0fca6ea1SDimitry Andric if (STM.getGeneration() >= AMDGPUSubtarget::GFX12) { 1151*0fca6ea1SDimitry Andric EmitResolvedOrExpr(SetBits(CurrentProgramInfo.ScratchBlocks, 1152*0fca6ea1SDimitry Andric /*Mask=*/0x3FFFF, /*Shift=*/12), 1153*0fca6ea1SDimitry Andric /*Size=*/4); 1154*0fca6ea1SDimitry Andric } else if (STM.getGeneration() == AMDGPUSubtarget::GFX11) { 1155*0fca6ea1SDimitry Andric EmitResolvedOrExpr(SetBits(CurrentProgramInfo.ScratchBlocks, 1156*0fca6ea1SDimitry Andric /*Mask=*/0x7FFF, /*Shift=*/12), 1157*0fca6ea1SDimitry Andric /*Size=*/4); 1158*0fca6ea1SDimitry Andric } else { 1159*0fca6ea1SDimitry Andric EmitResolvedOrExpr(SetBits(CurrentProgramInfo.ScratchBlocks, 1160*0fca6ea1SDimitry Andric /*Mask=*/0x1FFF, /*Shift=*/12), 1161*0fca6ea1SDimitry Andric /*Size=*/4); 1162*0fca6ea1SDimitry Andric } 11630b57cec5SDimitry Andric 11640b57cec5SDimitry Andric // TODO: Should probably note flat usage somewhere. SC emits a "FlatPtr32 = 11650b57cec5SDimitry Andric // 0" comment but I don't see a corresponding field in the register spec. 11660b57cec5SDimitry Andric } else { 11675ffd83dbSDimitry Andric OutStreamer->emitInt32(RsrcReg); 1168*0fca6ea1SDimitry Andric 1169*0fca6ea1SDimitry Andric const MCExpr *GPRBlocks = MCBinaryExpr::createOr( 1170*0fca6ea1SDimitry Andric SetBits(CurrentProgramInfo.VGPRBlocks, /*Mask=*/0x3F, /*Shift=*/0), 1171*0fca6ea1SDimitry Andric SetBits(CurrentProgramInfo.SGPRBlocks, /*Mask=*/0x0F, /*Shift=*/6), 1172*0fca6ea1SDimitry Andric MF.getContext()); 1173*0fca6ea1SDimitry Andric EmitResolvedOrExpr(GPRBlocks, /*Size=*/4); 11745ffd83dbSDimitry Andric OutStreamer->emitInt32(R_0286E8_SPI_TMPRING_SIZE); 1175*0fca6ea1SDimitry Andric 1176*0fca6ea1SDimitry Andric // Sets bits according to S_0286E8_WAVESIZE_* mask and shift values for the 1177*0fca6ea1SDimitry Andric // appropriate generation. 1178*0fca6ea1SDimitry Andric if (STM.getGeneration() >= AMDGPUSubtarget::GFX12) { 1179*0fca6ea1SDimitry Andric EmitResolvedOrExpr(SetBits(CurrentProgramInfo.ScratchBlocks, 1180*0fca6ea1SDimitry Andric /*Mask=*/0x3FFFF, /*Shift=*/12), 1181*0fca6ea1SDimitry Andric /*Size=*/4); 1182*0fca6ea1SDimitry Andric } else if (STM.getGeneration() == AMDGPUSubtarget::GFX11) { 1183*0fca6ea1SDimitry Andric EmitResolvedOrExpr(SetBits(CurrentProgramInfo.ScratchBlocks, 1184*0fca6ea1SDimitry Andric /*Mask=*/0x7FFF, /*Shift=*/12), 1185*0fca6ea1SDimitry Andric /*Size=*/4); 1186*0fca6ea1SDimitry Andric } else { 1187*0fca6ea1SDimitry Andric EmitResolvedOrExpr(SetBits(CurrentProgramInfo.ScratchBlocks, 1188*0fca6ea1SDimitry Andric /*Mask=*/0x1FFF, /*Shift=*/12), 1189*0fca6ea1SDimitry Andric /*Size=*/4); 1190*0fca6ea1SDimitry Andric } 11910b57cec5SDimitry Andric } 11920b57cec5SDimitry Andric 11930b57cec5SDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::AMDGPU_PS) { 11945ffd83dbSDimitry Andric OutStreamer->emitInt32(R_00B02C_SPI_SHADER_PGM_RSRC2_PS); 119581ad6265SDimitry Andric unsigned ExtraLDSSize = STM.getGeneration() >= AMDGPUSubtarget::GFX11 119681ad6265SDimitry Andric ? divideCeil(CurrentProgramInfo.LDSBlocks, 2) 119781ad6265SDimitry Andric : CurrentProgramInfo.LDSBlocks; 119881ad6265SDimitry Andric OutStreamer->emitInt32(S_00B02C_EXTRA_LDS_SIZE(ExtraLDSSize)); 11995ffd83dbSDimitry Andric OutStreamer->emitInt32(R_0286CC_SPI_PS_INPUT_ENA); 12005ffd83dbSDimitry Andric OutStreamer->emitInt32(MFI->getPSInputEnable()); 12015ffd83dbSDimitry Andric OutStreamer->emitInt32(R_0286D0_SPI_PS_INPUT_ADDR); 12025ffd83dbSDimitry Andric OutStreamer->emitInt32(MFI->getPSInputAddr()); 12030b57cec5SDimitry Andric } 12040b57cec5SDimitry Andric 12055ffd83dbSDimitry Andric OutStreamer->emitInt32(R_SPILLED_SGPRS); 12065ffd83dbSDimitry Andric OutStreamer->emitInt32(MFI->getNumSpilledSGPRs()); 12075ffd83dbSDimitry Andric OutStreamer->emitInt32(R_SPILLED_VGPRS); 12085ffd83dbSDimitry Andric OutStreamer->emitInt32(MFI->getNumSpilledVGPRs()); 12090b57cec5SDimitry Andric } 12100b57cec5SDimitry Andric 1211*0fca6ea1SDimitry Andric // Helper function to add common PAL Metadata 3.0+ 1212*0fca6ea1SDimitry Andric static void EmitPALMetadataCommon(AMDGPUPALMetadata *MD, 1213*0fca6ea1SDimitry Andric const SIProgramInfo &CurrentProgramInfo, 1214*0fca6ea1SDimitry Andric CallingConv::ID CC, const GCNSubtarget &ST) { 1215*0fca6ea1SDimitry Andric if (ST.hasIEEEMode()) 1216*0fca6ea1SDimitry Andric MD->setHwStage(CC, ".ieee_mode", (bool)CurrentProgramInfo.IEEEMode); 1217*0fca6ea1SDimitry Andric 1218*0fca6ea1SDimitry Andric MD->setHwStage(CC, ".wgp_mode", (bool)CurrentProgramInfo.WgpMode); 1219*0fca6ea1SDimitry Andric MD->setHwStage(CC, ".mem_ordered", (bool)CurrentProgramInfo.MemOrdered); 1220*0fca6ea1SDimitry Andric 1221*0fca6ea1SDimitry Andric if (AMDGPU::isCompute(CC)) { 1222*0fca6ea1SDimitry Andric MD->setHwStage(CC, ".trap_present", 1223*0fca6ea1SDimitry Andric (bool)CurrentProgramInfo.TrapHandlerEnable); 1224*0fca6ea1SDimitry Andric MD->setHwStage(CC, ".excp_en", CurrentProgramInfo.EXCPEnable); 1225*0fca6ea1SDimitry Andric } 1226*0fca6ea1SDimitry Andric 1227*0fca6ea1SDimitry Andric MD->setHwStage(CC, ".lds_size", 1228*0fca6ea1SDimitry Andric (unsigned)(CurrentProgramInfo.LdsSize * 1229*0fca6ea1SDimitry Andric getLdsDwGranularity(ST) * sizeof(uint32_t))); 1230*0fca6ea1SDimitry Andric } 1231*0fca6ea1SDimitry Andric 12320b57cec5SDimitry Andric // This is the equivalent of EmitProgramInfoSI above, but for when the OS type 12330b57cec5SDimitry Andric // is AMDPAL. It stores each compute/SPI register setting and other PAL 12340b57cec5SDimitry Andric // metadata items into the PALMD::Metadata, combining with any provided by the 12350b57cec5SDimitry Andric // frontend as LLVM metadata. Once all functions are written, the PAL metadata 12360b57cec5SDimitry Andric // is then written as a single block in the .note section. 12370b57cec5SDimitry Andric void AMDGPUAsmPrinter::EmitPALMetadata(const MachineFunction &MF, 12380b57cec5SDimitry Andric const SIProgramInfo &CurrentProgramInfo) { 12390b57cec5SDimitry Andric const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 12400b57cec5SDimitry Andric auto CC = MF.getFunction().getCallingConv(); 12410b57cec5SDimitry Andric auto MD = getTargetStreamer()->getPALMetadata(); 1242*0fca6ea1SDimitry Andric auto &Ctx = MF.getContext(); 12430b57cec5SDimitry Andric 12440b57cec5SDimitry Andric MD->setEntryPoint(CC, MF.getFunction().getName()); 1245*0fca6ea1SDimitry Andric MD->setNumUsedVgprs(CC, CurrentProgramInfo.NumVGPRsForWavesPerEU, Ctx); 124681ad6265SDimitry Andric 124781ad6265SDimitry Andric // Only set AGPRs for supported devices 124881ad6265SDimitry Andric const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>(); 124981ad6265SDimitry Andric if (STM.hasMAIInsts()) { 125081ad6265SDimitry Andric MD->setNumUsedAgprs(CC, CurrentProgramInfo.NumAccVGPR); 125181ad6265SDimitry Andric } 125281ad6265SDimitry Andric 1253*0fca6ea1SDimitry Andric MD->setNumUsedSgprs(CC, CurrentProgramInfo.NumSGPRsForWavesPerEU, Ctx); 125406c3fb27SDimitry Andric if (MD->getPALMajorVersion() < 3) { 1255*0fca6ea1SDimitry Andric MD->setRsrc1(CC, CurrentProgramInfo.getPGMRSrc1(CC, STM, Ctx), Ctx); 1256e8d8bef9SDimitry Andric if (AMDGPU::isCompute(CC)) { 1257*0fca6ea1SDimitry Andric MD->setRsrc2(CC, CurrentProgramInfo.getComputePGMRSrc2(Ctx), Ctx); 12580b57cec5SDimitry Andric } else { 1259*0fca6ea1SDimitry Andric const MCExpr *HasScratchBlocks = 1260*0fca6ea1SDimitry Andric MCBinaryExpr::createGT(CurrentProgramInfo.ScratchBlocks, 1261*0fca6ea1SDimitry Andric MCConstantExpr::create(0, Ctx), Ctx); 1262*0fca6ea1SDimitry Andric auto [Shift, Mask] = getShiftMask(C_00B84C_SCRATCH_EN); 1263*0fca6ea1SDimitry Andric MD->setRsrc2(CC, maskShiftSet(HasScratchBlocks, Mask, Shift, Ctx), Ctx); 12640b57cec5SDimitry Andric } 126506c3fb27SDimitry Andric } else { 126606c3fb27SDimitry Andric MD->setHwStage(CC, ".debug_mode", (bool)CurrentProgramInfo.DebugMode); 1267*0fca6ea1SDimitry Andric MD->setHwStage(CC, ".scratch_en", msgpack::Type::Boolean, 1268*0fca6ea1SDimitry Andric CurrentProgramInfo.ScratchEnable); 1269*0fca6ea1SDimitry Andric EmitPALMetadataCommon(MD, CurrentProgramInfo, CC, STM); 127006c3fb27SDimitry Andric } 127106c3fb27SDimitry Andric 12720b57cec5SDimitry Andric // ScratchSize is in bytes, 16 aligned. 1273*0fca6ea1SDimitry Andric MD->setScratchSize( 1274*0fca6ea1SDimitry Andric CC, 1275*0fca6ea1SDimitry Andric AMDGPUMCExpr::createAlignTo(CurrentProgramInfo.ScratchSize, 1276*0fca6ea1SDimitry Andric MCConstantExpr::create(16, Ctx), Ctx), 1277*0fca6ea1SDimitry Andric Ctx); 1278*0fca6ea1SDimitry Andric 12790b57cec5SDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::AMDGPU_PS) { 128081ad6265SDimitry Andric unsigned ExtraLDSSize = STM.getGeneration() >= AMDGPUSubtarget::GFX11 128181ad6265SDimitry Andric ? divideCeil(CurrentProgramInfo.LDSBlocks, 2) 128281ad6265SDimitry Andric : CurrentProgramInfo.LDSBlocks; 128306c3fb27SDimitry Andric if (MD->getPALMajorVersion() < 3) { 1284*0fca6ea1SDimitry Andric MD->setRsrc2( 1285*0fca6ea1SDimitry Andric CC, 1286*0fca6ea1SDimitry Andric MCConstantExpr::create(S_00B02C_EXTRA_LDS_SIZE(ExtraLDSSize), Ctx), 1287*0fca6ea1SDimitry Andric Ctx); 12880b57cec5SDimitry Andric MD->setSpiPsInputEna(MFI->getPSInputEnable()); 12890b57cec5SDimitry Andric MD->setSpiPsInputAddr(MFI->getPSInputAddr()); 129006c3fb27SDimitry Andric } else { 129106c3fb27SDimitry Andric // Graphics registers 129206c3fb27SDimitry Andric const unsigned ExtraLdsDwGranularity = 129306c3fb27SDimitry Andric STM.getGeneration() >= AMDGPUSubtarget::GFX11 ? 256 : 128; 129406c3fb27SDimitry Andric MD->setGraphicsRegisters( 129506c3fb27SDimitry Andric ".ps_extra_lds_size", 129606c3fb27SDimitry Andric (unsigned)(ExtraLDSSize * ExtraLdsDwGranularity * sizeof(uint32_t))); 129706c3fb27SDimitry Andric 129806c3fb27SDimitry Andric // Set PsInputEna and PsInputAddr .spi_ps_input_ena and .spi_ps_input_addr 129906c3fb27SDimitry Andric static StringLiteral const PsInputFields[] = { 130006c3fb27SDimitry Andric ".persp_sample_ena", ".persp_center_ena", 130106c3fb27SDimitry Andric ".persp_centroid_ena", ".persp_pull_model_ena", 130206c3fb27SDimitry Andric ".linear_sample_ena", ".linear_center_ena", 130306c3fb27SDimitry Andric ".linear_centroid_ena", ".line_stipple_tex_ena", 130406c3fb27SDimitry Andric ".pos_x_float_ena", ".pos_y_float_ena", 130506c3fb27SDimitry Andric ".pos_z_float_ena", ".pos_w_float_ena", 130606c3fb27SDimitry Andric ".front_face_ena", ".ancillary_ena", 130706c3fb27SDimitry Andric ".sample_coverage_ena", ".pos_fixed_pt_ena"}; 130806c3fb27SDimitry Andric unsigned PSInputEna = MFI->getPSInputEnable(); 130906c3fb27SDimitry Andric unsigned PSInputAddr = MFI->getPSInputAddr(); 131006c3fb27SDimitry Andric for (auto [Idx, Field] : enumerate(PsInputFields)) { 131106c3fb27SDimitry Andric MD->setGraphicsRegisters(".spi_ps_input_ena", Field, 131206c3fb27SDimitry Andric (bool)((PSInputEna >> Idx) & 1)); 131306c3fb27SDimitry Andric MD->setGraphicsRegisters(".spi_ps_input_addr", Field, 131406c3fb27SDimitry Andric (bool)((PSInputAddr >> Idx) & 1)); 131506c3fb27SDimitry Andric } 131606c3fb27SDimitry Andric } 13170b57cec5SDimitry Andric } 13180b57cec5SDimitry Andric 131906c3fb27SDimitry Andric // For version 3 and above the wave front size is already set in the metadata 132006c3fb27SDimitry Andric if (MD->getPALMajorVersion() < 3 && STM.isWave32()) 13210b57cec5SDimitry Andric MD->setWave32(MF.getFunction().getCallingConv()); 13220b57cec5SDimitry Andric } 13230b57cec5SDimitry Andric 1324e8d8bef9SDimitry Andric void AMDGPUAsmPrinter::emitPALFunctionMetadata(const MachineFunction &MF) { 1325e8d8bef9SDimitry Andric auto *MD = getTargetStreamer()->getPALMetadata(); 1326e8d8bef9SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 13275f757f3fSDimitry Andric StringRef FnName = MF.getFunction().getName(); 13285f757f3fSDimitry Andric MD->setFunctionScratchSize(FnName, MFI.getStackSize()); 13295f757f3fSDimitry Andric const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>(); 1330*0fca6ea1SDimitry Andric MCContext &Ctx = MF.getContext(); 1331fe6060f1SDimitry Andric 1332*0fca6ea1SDimitry Andric if (MD->getPALMajorVersion() < 3) { 1333e8d8bef9SDimitry Andric // Set compute registers 1334*0fca6ea1SDimitry Andric MD->setRsrc1( 1335*0fca6ea1SDimitry Andric CallingConv::AMDGPU_CS, 1336*0fca6ea1SDimitry Andric CurrentProgramInfo.getPGMRSrc1(CallingConv::AMDGPU_CS, ST, Ctx), Ctx); 1337*0fca6ea1SDimitry Andric MD->setRsrc2(CallingConv::AMDGPU_CS, 1338*0fca6ea1SDimitry Andric CurrentProgramInfo.getComputePGMRSrc2(Ctx), Ctx); 1339*0fca6ea1SDimitry Andric } else { 1340*0fca6ea1SDimitry Andric EmitPALMetadataCommon(MD, CurrentProgramInfo, CallingConv::AMDGPU_CS, ST); 1341*0fca6ea1SDimitry Andric } 1342fe6060f1SDimitry Andric 1343fe6060f1SDimitry Andric // Set optional info 13445f757f3fSDimitry Andric MD->setFunctionLdsSize(FnName, CurrentProgramInfo.LDSSize); 13455f757f3fSDimitry Andric MD->setFunctionNumUsedVgprs(FnName, CurrentProgramInfo.NumVGPRsForWavesPerEU); 13465f757f3fSDimitry Andric MD->setFunctionNumUsedSgprs(FnName, CurrentProgramInfo.NumSGPRsForWavesPerEU); 1347e8d8bef9SDimitry Andric } 1348e8d8bef9SDimitry Andric 13490b57cec5SDimitry Andric // This is supposed to be log2(Size) 13500b57cec5SDimitry Andric static amd_element_byte_size_t getElementByteSizeValue(unsigned Size) { 13510b57cec5SDimitry Andric switch (Size) { 13520b57cec5SDimitry Andric case 4: 13530b57cec5SDimitry Andric return AMD_ELEMENT_4_BYTES; 13540b57cec5SDimitry Andric case 8: 13550b57cec5SDimitry Andric return AMD_ELEMENT_8_BYTES; 13560b57cec5SDimitry Andric case 16: 13570b57cec5SDimitry Andric return AMD_ELEMENT_16_BYTES; 13580b57cec5SDimitry Andric default: 13590b57cec5SDimitry Andric llvm_unreachable("invalid private_element_size"); 13600b57cec5SDimitry Andric } 13610b57cec5SDimitry Andric } 13620b57cec5SDimitry Andric 1363*0fca6ea1SDimitry Andric void AMDGPUAsmPrinter::getAmdKernelCode(AMDGPUMCKernelCodeT &Out, 13640b57cec5SDimitry Andric const SIProgramInfo &CurrentProgramInfo, 13650b57cec5SDimitry Andric const MachineFunction &MF) const { 13660b57cec5SDimitry Andric const Function &F = MF.getFunction(); 13670b57cec5SDimitry Andric assert(F.getCallingConv() == CallingConv::AMDGPU_KERNEL || 13680b57cec5SDimitry Andric F.getCallingConv() == CallingConv::SPIR_KERNEL); 13690b57cec5SDimitry Andric 13700b57cec5SDimitry Andric const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 13710b57cec5SDimitry Andric const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>(); 1372*0fca6ea1SDimitry Andric MCContext &Ctx = MF.getContext(); 13730b57cec5SDimitry Andric 1374*0fca6ea1SDimitry Andric Out.initDefault(&STM, Ctx, /*InitMCExpr=*/false); 13750b57cec5SDimitry Andric 1376*0fca6ea1SDimitry Andric Out.compute_pgm_resource1_registers = 1377*0fca6ea1SDimitry Andric CurrentProgramInfo.getComputePGMRSrc1(STM, Ctx); 1378*0fca6ea1SDimitry Andric Out.compute_pgm_resource2_registers = 1379*0fca6ea1SDimitry Andric CurrentProgramInfo.getComputePGMRSrc2(Ctx); 13800b57cec5SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_IS_PTR64; 13810b57cec5SDimitry Andric 1382*0fca6ea1SDimitry Andric Out.is_dynamic_callstack = CurrentProgramInfo.DynamicCallStack; 13830b57cec5SDimitry Andric 1384*0fca6ea1SDimitry Andric AMD_HSA_BITS_SET(Out.code_properties, AMD_CODE_PROPERTY_PRIVATE_ELEMENT_SIZE, 1385e8d8bef9SDimitry Andric getElementByteSizeValue(STM.getMaxPrivateElementSize(true))); 13860b57cec5SDimitry Andric 13875f757f3fSDimitry Andric const GCNUserSGPRUsageInfo &UserSGPRInfo = MFI->getUserSGPRInfo(); 13885f757f3fSDimitry Andric if (UserSGPRInfo.hasPrivateSegmentBuffer()) { 1389*0fca6ea1SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER; 13900b57cec5SDimitry Andric } 13910b57cec5SDimitry Andric 13925f757f3fSDimitry Andric if (UserSGPRInfo.hasDispatchPtr()) 13930b57cec5SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_PTR; 13940b57cec5SDimitry Andric 13955f757f3fSDimitry Andric if (UserSGPRInfo.hasQueuePtr() && CodeObjectVersion < AMDGPU::AMDHSA_COV5) 13960b57cec5SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_QUEUE_PTR; 13970b57cec5SDimitry Andric 13985f757f3fSDimitry Andric if (UserSGPRInfo.hasKernargSegmentPtr()) 13990b57cec5SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_KERNARG_SEGMENT_PTR; 14000b57cec5SDimitry Andric 14015f757f3fSDimitry Andric if (UserSGPRInfo.hasDispatchID()) 14020b57cec5SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_ID; 14030b57cec5SDimitry Andric 14045f757f3fSDimitry Andric if (UserSGPRInfo.hasFlatScratchInit()) 14050b57cec5SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_FLAT_SCRATCH_INIT; 14060b57cec5SDimitry Andric 1407*0fca6ea1SDimitry Andric if (UserSGPRInfo.hasPrivateSegmentSize()) 1408*0fca6ea1SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_SIZE; 1409*0fca6ea1SDimitry Andric 14105f757f3fSDimitry Andric if (UserSGPRInfo.hasDispatchPtr()) 14110b57cec5SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_PTR; 14120b57cec5SDimitry Andric 14130b57cec5SDimitry Andric if (STM.isXNACKEnabled()) 14140b57cec5SDimitry Andric Out.code_properties |= AMD_CODE_PROPERTY_IS_XNACK_SUPPORTED; 14150b57cec5SDimitry Andric 14168bcb0991SDimitry Andric Align MaxKernArgAlign; 14170b57cec5SDimitry Andric Out.kernarg_segment_byte_size = STM.getKernArgSegmentSize(F, MaxKernArgAlign); 14180b57cec5SDimitry Andric Out.wavefront_sgpr_count = CurrentProgramInfo.NumSGPR; 14190b57cec5SDimitry Andric Out.workitem_vgpr_count = CurrentProgramInfo.NumVGPR; 14200b57cec5SDimitry Andric Out.workitem_private_segment_byte_size = CurrentProgramInfo.ScratchSize; 14210b57cec5SDimitry Andric Out.workgroup_group_segment_byte_size = CurrentProgramInfo.LDSSize; 14220b57cec5SDimitry Andric 14238bcb0991SDimitry Andric // kernarg_segment_alignment is specified as log of the alignment. 14248bcb0991SDimitry Andric // The minimum alignment is 16. 1425349cc55cSDimitry Andric // FIXME: The metadata treats the minimum as 4? 14268bcb0991SDimitry Andric Out.kernarg_segment_alignment = Log2(std::max(Align(16), MaxKernArgAlign)); 14270b57cec5SDimitry Andric } 14280b57cec5SDimitry Andric 14290b57cec5SDimitry Andric bool AMDGPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 14300b57cec5SDimitry Andric const char *ExtraCode, raw_ostream &O) { 14310b57cec5SDimitry Andric // First try the generic code, which knows about modifiers like 'c' and 'n'. 14320b57cec5SDimitry Andric if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O)) 14330b57cec5SDimitry Andric return false; 14340b57cec5SDimitry Andric 14350b57cec5SDimitry Andric if (ExtraCode && ExtraCode[0]) { 14360b57cec5SDimitry Andric if (ExtraCode[1] != 0) 14370b57cec5SDimitry Andric return true; // Unknown modifier. 14380b57cec5SDimitry Andric 14390b57cec5SDimitry Andric switch (ExtraCode[0]) { 14400b57cec5SDimitry Andric case 'r': 14410b57cec5SDimitry Andric break; 14420b57cec5SDimitry Andric default: 14430b57cec5SDimitry Andric return true; 14440b57cec5SDimitry Andric } 14450b57cec5SDimitry Andric } 14460b57cec5SDimitry Andric 14470b57cec5SDimitry Andric // TODO: Should be able to support other operand types like globals. 14480b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNo); 14490b57cec5SDimitry Andric if (MO.isReg()) { 14500b57cec5SDimitry Andric AMDGPUInstPrinter::printRegOperand(MO.getReg(), O, 14510b57cec5SDimitry Andric *MF->getSubtarget().getRegisterInfo()); 14520b57cec5SDimitry Andric return false; 1453*0fca6ea1SDimitry Andric } 1454*0fca6ea1SDimitry Andric if (MO.isImm()) { 14555ffd83dbSDimitry Andric int64_t Val = MO.getImm(); 14565ffd83dbSDimitry Andric if (AMDGPU::isInlinableIntLiteral(Val)) { 14575ffd83dbSDimitry Andric O << Val; 14585ffd83dbSDimitry Andric } else if (isUInt<16>(Val)) { 14595ffd83dbSDimitry Andric O << format("0x%" PRIx16, static_cast<uint16_t>(Val)); 14605ffd83dbSDimitry Andric } else if (isUInt<32>(Val)) { 14615ffd83dbSDimitry Andric O << format("0x%" PRIx32, static_cast<uint32_t>(Val)); 14625ffd83dbSDimitry Andric } else { 14635ffd83dbSDimitry Andric O << format("0x%" PRIx64, static_cast<uint64_t>(Val)); 14640b57cec5SDimitry Andric } 14655ffd83dbSDimitry Andric return false; 14665ffd83dbSDimitry Andric } 14670b57cec5SDimitry Andric return true; 14680b57cec5SDimitry Andric } 1469fe6060f1SDimitry Andric 1470fe6060f1SDimitry Andric void AMDGPUAsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const { 1471fe6060f1SDimitry Andric AU.addRequired<AMDGPUResourceUsageAnalysis>(); 1472fe6060f1SDimitry Andric AU.addPreserved<AMDGPUResourceUsageAnalysis>(); 1473fe6060f1SDimitry Andric AsmPrinter::getAnalysisUsage(AU); 1474fe6060f1SDimitry Andric } 1475fcaf7f86SDimitry Andric 1476fcaf7f86SDimitry Andric void AMDGPUAsmPrinter::emitResourceUsageRemarks( 1477fcaf7f86SDimitry Andric const MachineFunction &MF, const SIProgramInfo &CurrentProgramInfo, 1478fcaf7f86SDimitry Andric bool isModuleEntryFunction, bool hasMAIInsts) { 1479fcaf7f86SDimitry Andric if (!ORE) 1480fcaf7f86SDimitry Andric return; 1481fcaf7f86SDimitry Andric 1482fcaf7f86SDimitry Andric const char *Name = "kernel-resource-usage"; 1483fcaf7f86SDimitry Andric const char *Indent = " "; 1484fcaf7f86SDimitry Andric 1485fcaf7f86SDimitry Andric // If the remark is not specifically enabled, do not output to yaml 1486fcaf7f86SDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 1487fcaf7f86SDimitry Andric if (!Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(Name)) 1488fcaf7f86SDimitry Andric return; 1489fcaf7f86SDimitry Andric 1490*0fca6ea1SDimitry Andric // Currently non-kernel functions have no resources to emit. 1491*0fca6ea1SDimitry Andric if (!isEntryFunctionCC(MF.getFunction().getCallingConv())) 1492*0fca6ea1SDimitry Andric return; 1493*0fca6ea1SDimitry Andric 1494fcaf7f86SDimitry Andric auto EmitResourceUsageRemark = [&](StringRef RemarkName, 1495fcaf7f86SDimitry Andric StringRef RemarkLabel, auto Argument) { 1496fcaf7f86SDimitry Andric // Add an indent for every line besides the line with the kernel name. This 1497fcaf7f86SDimitry Andric // makes it easier to tell which resource usage go with which kernel since 1498fcaf7f86SDimitry Andric // the kernel name will always be displayed first. 1499fcaf7f86SDimitry Andric std::string LabelStr = RemarkLabel.str() + ": "; 1500*0fca6ea1SDimitry Andric if (RemarkName != "FunctionName") 1501fcaf7f86SDimitry Andric LabelStr = Indent + LabelStr; 1502fcaf7f86SDimitry Andric 1503fcaf7f86SDimitry Andric ORE->emit([&]() { 1504fcaf7f86SDimitry Andric return MachineOptimizationRemarkAnalysis(Name, RemarkName, 1505fcaf7f86SDimitry Andric MF.getFunction().getSubprogram(), 1506fcaf7f86SDimitry Andric &MF.front()) 1507fcaf7f86SDimitry Andric << LabelStr << ore::NV(RemarkName, Argument); 1508fcaf7f86SDimitry Andric }); 1509fcaf7f86SDimitry Andric }; 1510fcaf7f86SDimitry Andric 1511fcaf7f86SDimitry Andric // FIXME: Formatting here is pretty nasty because clang does not accept 1512fcaf7f86SDimitry Andric // newlines from diagnostics. This forces us to emit multiple diagnostic 1513fcaf7f86SDimitry Andric // remarks to simulate newlines. If and when clang does accept newlines, this 1514fcaf7f86SDimitry Andric // formatting should be aggregated into one remark with newlines to avoid 1515fcaf7f86SDimitry Andric // printing multiple diagnostic location and diag opts. 1516fcaf7f86SDimitry Andric EmitResourceUsageRemark("FunctionName", "Function Name", 1517fcaf7f86SDimitry Andric MF.getFunction().getName()); 1518*0fca6ea1SDimitry Andric EmitResourceUsageRemark("NumSGPR", "SGPRs", 1519*0fca6ea1SDimitry Andric getMCExprStr(CurrentProgramInfo.NumSGPR)); 1520*0fca6ea1SDimitry Andric EmitResourceUsageRemark("NumVGPR", "VGPRs", 1521*0fca6ea1SDimitry Andric getMCExprStr(CurrentProgramInfo.NumArchVGPR)); 1522*0fca6ea1SDimitry Andric if (hasMAIInsts) { 1523*0fca6ea1SDimitry Andric EmitResourceUsageRemark("NumAGPR", "AGPRs", 1524*0fca6ea1SDimitry Andric getMCExprStr(CurrentProgramInfo.NumAccVGPR)); 1525*0fca6ea1SDimitry Andric } 1526fcaf7f86SDimitry Andric EmitResourceUsageRemark("ScratchSize", "ScratchSize [bytes/lane]", 1527*0fca6ea1SDimitry Andric getMCExprStr(CurrentProgramInfo.ScratchSize)); 1528*0fca6ea1SDimitry Andric int64_t DynStack; 1529*0fca6ea1SDimitry Andric bool DynStackEvaluatable = 1530*0fca6ea1SDimitry Andric CurrentProgramInfo.DynamicCallStack->evaluateAsAbsolute(DynStack); 15315f757f3fSDimitry Andric StringRef DynamicStackStr = 1532*0fca6ea1SDimitry Andric DynStackEvaluatable && DynStack ? "True" : "False"; 15335f757f3fSDimitry Andric EmitResourceUsageRemark("DynamicStack", "Dynamic Stack", DynamicStackStr); 1534fcaf7f86SDimitry Andric EmitResourceUsageRemark("Occupancy", "Occupancy [waves/SIMD]", 1535*0fca6ea1SDimitry Andric getMCExprStr(CurrentProgramInfo.Occupancy)); 1536fcaf7f86SDimitry Andric EmitResourceUsageRemark("SGPRSpill", "SGPRs Spill", 1537fcaf7f86SDimitry Andric CurrentProgramInfo.SGPRSpill); 1538fcaf7f86SDimitry Andric EmitResourceUsageRemark("VGPRSpill", "VGPRs Spill", 1539fcaf7f86SDimitry Andric CurrentProgramInfo.VGPRSpill); 1540fcaf7f86SDimitry Andric if (isModuleEntryFunction) 1541fcaf7f86SDimitry Andric EmitResourceUsageRemark("BytesLDS", "LDS Size [bytes/block]", 1542fcaf7f86SDimitry Andric CurrentProgramInfo.LDSSize); 1543fcaf7f86SDimitry Andric } 1544